xref: /src/contrib/llvm-project/llvm/lib/CodeGen/MachineScheduler.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
163faed5bSDimitry Andric //===- MachineScheduler.cpp - Machine Instruction Scheduler ---------------===//
263faed5bSDimitry Andric //
3e6d15924SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e6d15924SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5e6d15924SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
663faed5bSDimitry Andric //
763faed5bSDimitry Andric //===----------------------------------------------------------------------===//
863faed5bSDimitry Andric //
963faed5bSDimitry Andric // MachineScheduler schedules machine instructions after phi elimination. It
1063faed5bSDimitry Andric // preserves LiveIntervals so it can be invoked before register allocation.
1163faed5bSDimitry Andric //
1263faed5bSDimitry Andric //===----------------------------------------------------------------------===//
1363faed5bSDimitry Andric 
147ab83427SDimitry Andric #include "llvm/CodeGen/MachineScheduler.h"
1571d5a254SDimitry Andric #include "llvm/ADT/ArrayRef.h"
1671d5a254SDimitry Andric #include "llvm/ADT/BitVector.h"
1771d5a254SDimitry Andric #include "llvm/ADT/DenseMap.h"
184a16efa3SDimitry Andric #include "llvm/ADT/PriorityQueue.h"
1971d5a254SDimitry Andric #include "llvm/ADT/STLExtras.h"
207ab83427SDimitry Andric #include "llvm/ADT/SmallVector.h"
21b60736ecSDimitry Andric #include "llvm/ADT/Statistic.h"
227ab83427SDimitry Andric #include "llvm/ADT/iterator_range.h"
234a16efa3SDimitry Andric #include "llvm/Analysis/AliasAnalysis.h"
2471d5a254SDimitry Andric #include "llvm/CodeGen/LiveInterval.h"
25044eb2f6SDimitry Andric #include "llvm/CodeGen/LiveIntervals.h"
2671d5a254SDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h"
274a16efa3SDimitry Andric #include "llvm/CodeGen/MachineDominators.h"
2871d5a254SDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
2971d5a254SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
3071d5a254SDimitry Andric #include "llvm/CodeGen/MachineInstr.h"
314a16efa3SDimitry Andric #include "llvm/CodeGen/MachineLoopInfo.h"
3271d5a254SDimitry Andric #include "llvm/CodeGen/MachineOperand.h"
3371d5a254SDimitry Andric #include "llvm/CodeGen/MachinePassRegistry.h"
34f8af5cf6SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
3558b69754SDimitry Andric #include "llvm/CodeGen/RegisterClassInfo.h"
367ab83427SDimitry Andric #include "llvm/CodeGen/RegisterPressure.h"
3771d5a254SDimitry Andric #include "llvm/CodeGen/ScheduleDAG.h"
3871d5a254SDimitry Andric #include "llvm/CodeGen/ScheduleDAGInstrs.h"
3971d5a254SDimitry Andric #include "llvm/CodeGen/ScheduleDAGMutation.h"
404a16efa3SDimitry Andric #include "llvm/CodeGen/ScheduleDFS.h"
4158b69754SDimitry Andric #include "llvm/CodeGen/ScheduleHazardRecognizer.h"
4271d5a254SDimitry Andric #include "llvm/CodeGen/SlotIndexes.h"
43d8e91e46SDimitry Andric #include "llvm/CodeGen/TargetFrameLowering.h"
44044eb2f6SDimitry Andric #include "llvm/CodeGen/TargetInstrInfo.h"
45044eb2f6SDimitry Andric #include "llvm/CodeGen/TargetLowering.h"
4601095a5dSDimitry Andric #include "llvm/CodeGen/TargetPassConfig.h"
47044eb2f6SDimitry Andric #include "llvm/CodeGen/TargetRegisterInfo.h"
4871d5a254SDimitry Andric #include "llvm/CodeGen/TargetSchedule.h"
49044eb2f6SDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h"
50ac9a064cSDimitry Andric #include "llvm/CodeGenTypes/MachineValueType.h"
51eb11fae6SDimitry Andric #include "llvm/Config/llvm-config.h"
52706b4fc4SDimitry Andric #include "llvm/InitializePasses.h"
5371d5a254SDimitry Andric #include "llvm/MC/LaneBitmask.h"
5471d5a254SDimitry Andric #include "llvm/Pass.h"
5563faed5bSDimitry Andric #include "llvm/Support/CommandLine.h"
5671d5a254SDimitry Andric #include "llvm/Support/Compiler.h"
5763faed5bSDimitry Andric #include "llvm/Support/Debug.h"
5863faed5bSDimitry Andric #include "llvm/Support/ErrorHandling.h"
594a16efa3SDimitry Andric #include "llvm/Support/GraphWriter.h"
6063faed5bSDimitry Andric #include "llvm/Support/raw_ostream.h"
6171d5a254SDimitry Andric #include <algorithm>
6271d5a254SDimitry Andric #include <cassert>
6371d5a254SDimitry Andric #include <cstdint>
6471d5a254SDimitry Andric #include <iterator>
6571d5a254SDimitry Andric #include <limits>
6671d5a254SDimitry Andric #include <memory>
6771d5a254SDimitry Andric #include <string>
6871d5a254SDimitry Andric #include <tuple>
6971d5a254SDimitry Andric #include <utility>
7071d5a254SDimitry Andric #include <vector>
7163faed5bSDimitry Andric 
7263faed5bSDimitry Andric using namespace llvm;
7363faed5bSDimitry Andric 
74ab44ce3dSDimitry Andric #define DEBUG_TYPE "machine-scheduler"
755ca98fd9SDimitry Andric 
76b60736ecSDimitry Andric STATISTIC(NumClustered, "Number of load/store pairs clustered");
77b60736ecSDimitry Andric 
78522600a2SDimitry Andric namespace llvm {
7971d5a254SDimitry Andric 
80522600a2SDimitry Andric cl::opt<bool> ForceTopDown("misched-topdown", cl::Hidden,
8163faed5bSDimitry Andric                            cl::desc("Force top-down list scheduling"));
82522600a2SDimitry Andric cl::opt<bool> ForceBottomUp("misched-bottomup", cl::Hidden,
8363faed5bSDimitry Andric                             cl::desc("Force bottom-up list scheduling"));
84ac9a064cSDimitry Andric namespace MISchedPostRASched {
85ac9a064cSDimitry Andric enum Direction {
86ac9a064cSDimitry Andric   TopDown,
87ac9a064cSDimitry Andric   BottomUp,
88ac9a064cSDimitry Andric   Bidirectional,
89ac9a064cSDimitry Andric };
90ac9a064cSDimitry Andric } // end namespace MISchedPostRASched
91ac9a064cSDimitry Andric cl::opt<MISchedPostRASched::Direction> PostRADirection(
92ac9a064cSDimitry Andric     "misched-postra-direction", cl::Hidden,
93ac9a064cSDimitry Andric     cl::desc("Post reg-alloc list scheduling direction"),
94ac9a064cSDimitry Andric     // Default to top-down because it was implemented first and existing targets
95ac9a064cSDimitry Andric     // expect that behavior by default.
96ac9a064cSDimitry Andric     cl::init(MISchedPostRASched::TopDown),
97ac9a064cSDimitry Andric     cl::values(
98ac9a064cSDimitry Andric         clEnumValN(MISchedPostRASched::TopDown, "topdown",
99ac9a064cSDimitry Andric                    "Force top-down post reg-alloc list scheduling"),
100ac9a064cSDimitry Andric         clEnumValN(MISchedPostRASched::BottomUp, "bottomup",
101ac9a064cSDimitry Andric                    "Force bottom-up post reg-alloc list scheduling"),
102ac9a064cSDimitry Andric         clEnumValN(MISchedPostRASched::Bidirectional, "bidirectional",
103ac9a064cSDimitry Andric                    "Force bidirectional post reg-alloc list scheduling")));
10467c32a98SDimitry Andric cl::opt<bool>
10567c32a98SDimitry Andric DumpCriticalPathLength("misched-dcpl", cl::Hidden,
10667c32a98SDimitry Andric                        cl::desc("Print critical path length to stdout"));
10771d5a254SDimitry Andric 
1081d5ae102SDimitry Andric cl::opt<bool> VerifyScheduling(
1091d5ae102SDimitry Andric     "verify-misched", cl::Hidden,
1101d5ae102SDimitry Andric     cl::desc("Verify machine instrs before and after machine scheduling"));
1111d5ae102SDimitry Andric 
11277fc4c14SDimitry Andric #ifndef NDEBUG
11377fc4c14SDimitry Andric cl::opt<bool> ViewMISchedDAGs(
11477fc4c14SDimitry Andric     "view-misched-dags", cl::Hidden,
11577fc4c14SDimitry Andric     cl::desc("Pop up a window to show MISched dags after they are processed"));
1161f917f69SDimitry Andric cl::opt<bool> PrintDAGs("misched-print-dags", cl::Hidden,
1171f917f69SDimitry Andric                         cl::desc("Print schedule DAGs"));
118e3b55780SDimitry Andric cl::opt<bool> MISchedDumpReservedCycles(
119e3b55780SDimitry Andric     "misched-dump-reserved-cycles", cl::Hidden, cl::init(false),
120e3b55780SDimitry Andric     cl::desc("Dump resource usage at schedule boundary."));
1217fa27ce4SDimitry Andric cl::opt<bool> MischedDetailResourceBooking(
1227fa27ce4SDimitry Andric     "misched-detail-resource-booking", cl::Hidden, cl::init(false),
1237fa27ce4SDimitry Andric     cl::desc("Show details of invoking getNextResoufceCycle."));
12477fc4c14SDimitry Andric #else
12577fc4c14SDimitry Andric const bool ViewMISchedDAGs = false;
1261f917f69SDimitry Andric const bool PrintDAGs = false;
1277fa27ce4SDimitry Andric const bool MischedDetailResourceBooking = false;
128e3b55780SDimitry Andric #ifdef LLVM_ENABLE_DUMP
129e3b55780SDimitry Andric const bool MISchedDumpReservedCycles = false;
130e3b55780SDimitry Andric #endif // LLVM_ENABLE_DUMP
13177fc4c14SDimitry Andric #endif // NDEBUG
13277fc4c14SDimitry Andric 
13371d5a254SDimitry Andric } // end namespace llvm
13463faed5bSDimitry Andric 
13563faed5bSDimitry Andric #ifndef NDEBUG
136dd58ef01SDimitry Andric /// In some situations a few uninteresting nodes depend on nearly all other
137dd58ef01SDimitry Andric /// nodes in the graph, provide a cutoff to hide them.
138dd58ef01SDimitry Andric static cl::opt<unsigned> ViewMISchedCutoff("view-misched-cutoff", cl::Hidden,
139dd58ef01SDimitry Andric   cl::desc("Hide nodes with more predecessor/successor than cutoff"));
140dd58ef01SDimitry Andric 
14163faed5bSDimitry Andric static cl::opt<unsigned> MISchedCutoff("misched-cutoff", cl::Hidden,
14263faed5bSDimitry Andric   cl::desc("Stop scheduling after N instructions"), cl::init(~0U));
1435ca98fd9SDimitry Andric 
1445ca98fd9SDimitry Andric static cl::opt<std::string> SchedOnlyFunc("misched-only-func", cl::Hidden,
1455ca98fd9SDimitry Andric   cl::desc("Only schedule this function"));
1465ca98fd9SDimitry Andric static cl::opt<unsigned> SchedOnlyBlock("misched-only-block", cl::Hidden,
1475ca98fd9SDimitry Andric                                         cl::desc("Only schedule this MBB#"));
14863faed5bSDimitry Andric #endif // NDEBUG
14963faed5bSDimitry Andric 
15001095a5dSDimitry Andric /// Avoid quadratic complexity in unusually large basic blocks by limiting the
15101095a5dSDimitry Andric /// size of the ready lists.
15201095a5dSDimitry Andric static cl::opt<unsigned> ReadyListLimit("misched-limit", cl::Hidden,
15301095a5dSDimitry Andric   cl::desc("Limit ready list to N instructions"), cl::init(256));
15401095a5dSDimitry Andric 
155f8af5cf6SDimitry Andric static cl::opt<bool> EnableRegPressure("misched-regpressure", cl::Hidden,
156f8af5cf6SDimitry Andric   cl::desc("Enable register pressure scheduling."), cl::init(true));
157f8af5cf6SDimitry Andric 
158f8af5cf6SDimitry Andric static cl::opt<bool> EnableCyclicPath("misched-cyclicpath", cl::Hidden,
159f8af5cf6SDimitry Andric   cl::desc("Enable cyclic critical path analysis."), cl::init(true));
16059d6cff9SDimitry Andric 
16101095a5dSDimitry Andric static cl::opt<bool> EnableMemOpCluster("misched-cluster", cl::Hidden,
16201095a5dSDimitry Andric                                         cl::desc("Enable memop clustering."),
16301095a5dSDimitry Andric                                         cl::init(true));
164b60736ecSDimitry Andric static cl::opt<bool>
165b60736ecSDimitry Andric     ForceFastCluster("force-fast-cluster", cl::Hidden,
166b60736ecSDimitry Andric                      cl::desc("Switch to fast cluster algorithm with the lost "
167b60736ecSDimitry Andric                               "of some fusion opportunities"),
168b60736ecSDimitry Andric                      cl::init(false));
169b60736ecSDimitry Andric static cl::opt<unsigned>
170b60736ecSDimitry Andric     FastClusterThreshold("fast-cluster-threshold", cl::Hidden,
171b60736ecSDimitry Andric                          cl::desc("The threshold for fast cluster"),
172b60736ecSDimitry Andric                          cl::init(1000));
1734a16efa3SDimitry Andric 
1747fa27ce4SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
1757fa27ce4SDimitry Andric static cl::opt<bool> MISchedDumpScheduleTrace(
1767fa27ce4SDimitry Andric     "misched-dump-schedule-trace", cl::Hidden, cl::init(false),
1777fa27ce4SDimitry Andric     cl::desc("Dump resource usage at schedule boundary."));
1787fa27ce4SDimitry Andric static cl::opt<unsigned>
1797fa27ce4SDimitry Andric     HeaderColWidth("misched-dump-schedule-trace-col-header-width", cl::Hidden,
1807fa27ce4SDimitry Andric                    cl::desc("Set width of the columns with "
1817fa27ce4SDimitry Andric                             "the resources and schedule units"),
1827fa27ce4SDimitry Andric                    cl::init(19));
1837fa27ce4SDimitry Andric static cl::opt<unsigned>
1847fa27ce4SDimitry Andric     ColWidth("misched-dump-schedule-trace-col-width", cl::Hidden,
1857fa27ce4SDimitry Andric              cl::desc("Set width of the columns showing resource booking."),
1867fa27ce4SDimitry Andric              cl::init(5));
1877fa27ce4SDimitry Andric static cl::opt<bool> MISchedSortResourcesInTrace(
1887fa27ce4SDimitry Andric     "misched-sort-resources-in-trace", cl::Hidden, cl::init(true),
1897fa27ce4SDimitry Andric     cl::desc("Sort the resources printed in the dump trace"));
1907fa27ce4SDimitry Andric #endif
1917fa27ce4SDimitry Andric 
1927fa27ce4SDimitry Andric static cl::opt<unsigned>
1937fa27ce4SDimitry Andric     MIResourceCutOff("misched-resource-cutoff", cl::Hidden,
1947fa27ce4SDimitry Andric                      cl::desc("Number of intervals to track"), cl::init(10));
1957fa27ce4SDimitry Andric 
1964a16efa3SDimitry Andric // DAG subtrees must have at least this many nodes.
1974a16efa3SDimitry Andric static const unsigned MinSubtreeSize = 8;
198522600a2SDimitry Andric 
199f8af5cf6SDimitry Andric // Pin the vtables to this file.
anchor()200f8af5cf6SDimitry Andric void MachineSchedStrategy::anchor() {}
20171d5a254SDimitry Andric 
anchor()202f8af5cf6SDimitry Andric void ScheduleDAGMutation::anchor() {}
203f8af5cf6SDimitry Andric 
20463faed5bSDimitry Andric //===----------------------------------------------------------------------===//
20563faed5bSDimitry Andric // Machine Instruction Scheduling Pass and Registry
20663faed5bSDimitry Andric //===----------------------------------------------------------------------===//
20763faed5bSDimitry Andric 
MachineSchedContext()20871d5a254SDimitry Andric MachineSchedContext::MachineSchedContext() {
20958b69754SDimitry Andric   RegClassInfo = new RegisterClassInfo();
21058b69754SDimitry Andric }
21158b69754SDimitry Andric 
~MachineSchedContext()21258b69754SDimitry Andric MachineSchedContext::~MachineSchedContext() {
21358b69754SDimitry Andric   delete RegClassInfo;
21458b69754SDimitry Andric }
21558b69754SDimitry Andric 
21663faed5bSDimitry Andric namespace {
21771d5a254SDimitry Andric 
2185ca98fd9SDimitry Andric /// Base class for a machine scheduler class that can run at any point.
2195ca98fd9SDimitry Andric class MachineSchedulerBase : public MachineSchedContext,
22063faed5bSDimitry Andric                              public MachineFunctionPass {
22163faed5bSDimitry Andric public:
MachineSchedulerBase(char & ID)2225ca98fd9SDimitry Andric   MachineSchedulerBase(char &ID): MachineFunctionPass(ID) {}
2235ca98fd9SDimitry Andric 
2245ca98fd9SDimitry Andric   void print(raw_ostream &O, const Module* = nullptr) const override;
2255ca98fd9SDimitry Andric 
2265ca98fd9SDimitry Andric protected:
227dd58ef01SDimitry Andric   void scheduleRegions(ScheduleDAGInstrs &Scheduler, bool FixKillFlags);
2285ca98fd9SDimitry Andric };
2295ca98fd9SDimitry Andric 
2305ca98fd9SDimitry Andric /// MachineScheduler runs after coalescing and before register allocation.
2315ca98fd9SDimitry Andric class MachineScheduler : public MachineSchedulerBase {
2325ca98fd9SDimitry Andric public:
23363faed5bSDimitry Andric   MachineScheduler();
23463faed5bSDimitry Andric 
2355ca98fd9SDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override;
23663faed5bSDimitry Andric 
2375ca98fd9SDimitry Andric   bool runOnMachineFunction(MachineFunction&) override;
23863faed5bSDimitry Andric 
23963faed5bSDimitry Andric   static char ID; // Class identification, replacement for typeinfo
240f8af5cf6SDimitry Andric 
241f8af5cf6SDimitry Andric protected:
242f8af5cf6SDimitry Andric   ScheduleDAGInstrs *createMachineScheduler();
24363faed5bSDimitry Andric };
2445ca98fd9SDimitry Andric 
2455ca98fd9SDimitry Andric /// PostMachineScheduler runs after shortly before code emission.
2465ca98fd9SDimitry Andric class PostMachineScheduler : public MachineSchedulerBase {
2475ca98fd9SDimitry Andric public:
2485ca98fd9SDimitry Andric   PostMachineScheduler();
2495ca98fd9SDimitry Andric 
2505ca98fd9SDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override;
2515ca98fd9SDimitry Andric 
2525ca98fd9SDimitry Andric   bool runOnMachineFunction(MachineFunction&) override;
2535ca98fd9SDimitry Andric 
2545ca98fd9SDimitry Andric   static char ID; // Class identification, replacement for typeinfo
2555ca98fd9SDimitry Andric 
2565ca98fd9SDimitry Andric protected:
2575ca98fd9SDimitry Andric   ScheduleDAGInstrs *createPostMachineScheduler();
2585ca98fd9SDimitry Andric };
25971d5a254SDimitry Andric 
26071d5a254SDimitry Andric } // end anonymous namespace
26163faed5bSDimitry Andric 
26263faed5bSDimitry Andric char MachineScheduler::ID = 0;
26363faed5bSDimitry Andric 
26463faed5bSDimitry Andric char &llvm::MachineSchedulerID = MachineScheduler::ID;
26563faed5bSDimitry Andric 
266ab44ce3dSDimitry Andric INITIALIZE_PASS_BEGIN(MachineScheduler, DEBUG_TYPE,
26763faed5bSDimitry Andric                       "Machine Instruction Scheduler", false, false)
INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass)268dd58ef01SDimitry Andric INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass)
269ac9a064cSDimitry Andric INITIALIZE_PASS_DEPENDENCY(MachineDominatorTreeWrapperPass)
270ac9a064cSDimitry Andric INITIALIZE_PASS_DEPENDENCY(MachineLoopInfoWrapperPass)
271ac9a064cSDimitry Andric INITIALIZE_PASS_DEPENDENCY(SlotIndexesWrapperPass)
272ac9a064cSDimitry Andric INITIALIZE_PASS_DEPENDENCY(LiveIntervalsWrapperPass)
273ab44ce3dSDimitry Andric INITIALIZE_PASS_END(MachineScheduler, DEBUG_TYPE,
27463faed5bSDimitry Andric                     "Machine Instruction Scheduler", false, false)
27563faed5bSDimitry Andric 
276044eb2f6SDimitry Andric MachineScheduler::MachineScheduler() : MachineSchedulerBase(ID) {
27763faed5bSDimitry Andric   initializeMachineSchedulerPass(*PassRegistry::getPassRegistry());
27863faed5bSDimitry Andric }
27963faed5bSDimitry Andric 
getAnalysisUsage(AnalysisUsage & AU) const28063faed5bSDimitry Andric void MachineScheduler::getAnalysisUsage(AnalysisUsage &AU) const {
28163faed5bSDimitry Andric   AU.setPreservesCFG();
282ac9a064cSDimitry Andric   AU.addRequired<MachineDominatorTreeWrapperPass>();
283ac9a064cSDimitry Andric   AU.addRequired<MachineLoopInfoWrapperPass>();
284dd58ef01SDimitry Andric   AU.addRequired<AAResultsWrapperPass>();
28563faed5bSDimitry Andric   AU.addRequired<TargetPassConfig>();
286ac9a064cSDimitry Andric   AU.addRequired<SlotIndexesWrapperPass>();
287ac9a064cSDimitry Andric   AU.addPreserved<SlotIndexesWrapperPass>();
288ac9a064cSDimitry Andric   AU.addRequired<LiveIntervalsWrapperPass>();
289ac9a064cSDimitry Andric   AU.addPreserved<LiveIntervalsWrapperPass>();
29063faed5bSDimitry Andric   MachineFunctionPass::getAnalysisUsage(AU);
29163faed5bSDimitry Andric }
29263faed5bSDimitry Andric 
2935ca98fd9SDimitry Andric char PostMachineScheduler::ID = 0;
2945ca98fd9SDimitry Andric 
2955ca98fd9SDimitry Andric char &llvm::PostMachineSchedulerID = PostMachineScheduler::ID;
2965ca98fd9SDimitry Andric 
297b60736ecSDimitry Andric INITIALIZE_PASS_BEGIN(PostMachineScheduler, "postmisched",
298b60736ecSDimitry Andric                       "PostRA Machine Instruction Scheduler", false, false)
INITIALIZE_PASS_DEPENDENCY(MachineDominatorTreeWrapperPass)299ac9a064cSDimitry Andric INITIALIZE_PASS_DEPENDENCY(MachineDominatorTreeWrapperPass)
300ac9a064cSDimitry Andric INITIALIZE_PASS_DEPENDENCY(MachineLoopInfoWrapperPass)
301b60736ecSDimitry Andric INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass)
302b60736ecSDimitry Andric INITIALIZE_PASS_END(PostMachineScheduler, "postmisched",
3035ca98fd9SDimitry Andric                     "PostRA Machine Instruction Scheduler", false, false)
3045ca98fd9SDimitry Andric 
305044eb2f6SDimitry Andric PostMachineScheduler::PostMachineScheduler() : MachineSchedulerBase(ID) {
3065ca98fd9SDimitry Andric   initializePostMachineSchedulerPass(*PassRegistry::getPassRegistry());
3075ca98fd9SDimitry Andric }
3085ca98fd9SDimitry Andric 
getAnalysisUsage(AnalysisUsage & AU) const3095ca98fd9SDimitry Andric void PostMachineScheduler::getAnalysisUsage(AnalysisUsage &AU) const {
3105ca98fd9SDimitry Andric   AU.setPreservesCFG();
311ac9a064cSDimitry Andric   AU.addRequired<MachineDominatorTreeWrapperPass>();
312ac9a064cSDimitry Andric   AU.addRequired<MachineLoopInfoWrapperPass>();
313706b4fc4SDimitry Andric   AU.addRequired<AAResultsWrapperPass>();
3145ca98fd9SDimitry Andric   AU.addRequired<TargetPassConfig>();
3155ca98fd9SDimitry Andric   MachineFunctionPass::getAnalysisUsage(AU);
3165ca98fd9SDimitry Andric }
3175ca98fd9SDimitry Andric 
318d8e91e46SDimitry Andric MachinePassRegistry<MachineSchedRegistry::ScheduleDAGCtor>
319d8e91e46SDimitry Andric     MachineSchedRegistry::Registry;
32063faed5bSDimitry Andric 
32163faed5bSDimitry Andric /// A dummy default scheduler factory indicates whether the scheduler
32263faed5bSDimitry Andric /// is overridden on the command line.
useDefaultMachineSched(MachineSchedContext * C)32363faed5bSDimitry Andric static ScheduleDAGInstrs *useDefaultMachineSched(MachineSchedContext *C) {
3245ca98fd9SDimitry Andric   return nullptr;
32563faed5bSDimitry Andric }
32663faed5bSDimitry Andric 
32763faed5bSDimitry Andric /// MachineSchedOpt allows command line selection of the scheduler.
32863faed5bSDimitry Andric static cl::opt<MachineSchedRegistry::ScheduleDAGCtor, false,
32963faed5bSDimitry Andric                RegisterPassParser<MachineSchedRegistry>>
33063faed5bSDimitry Andric MachineSchedOpt("misched",
33163faed5bSDimitry Andric                 cl::init(&useDefaultMachineSched), cl::Hidden,
33263faed5bSDimitry Andric                 cl::desc("Machine instruction scheduler to use"));
33363faed5bSDimitry Andric 
33463faed5bSDimitry Andric static MachineSchedRegistry
33563faed5bSDimitry Andric DefaultSchedRegistry("default", "Use the target's default scheduler choice.",
33663faed5bSDimitry Andric                      useDefaultMachineSched);
33763faed5bSDimitry Andric 
3385a5ac124SDimitry Andric static cl::opt<bool> EnableMachineSched(
3395a5ac124SDimitry Andric     "enable-misched",
3405a5ac124SDimitry Andric     cl::desc("Enable the machine instruction scheduling pass."), cl::init(true),
3415a5ac124SDimitry Andric     cl::Hidden);
3425a5ac124SDimitry Andric 
34301095a5dSDimitry Andric static cl::opt<bool> EnablePostRAMachineSched(
34401095a5dSDimitry Andric     "enable-post-misched",
34501095a5dSDimitry Andric     cl::desc("Enable the post-ra machine instruction scheduling pass."),
34601095a5dSDimitry Andric     cl::init(true), cl::Hidden);
34701095a5dSDimitry Andric 
34858b69754SDimitry Andric /// Decrement this iterator until reaching the top or a non-debug instr.
349f8af5cf6SDimitry Andric static MachineBasicBlock::const_iterator
priorNonDebug(MachineBasicBlock::const_iterator I,MachineBasicBlock::const_iterator Beg)350f8af5cf6SDimitry Andric priorNonDebug(MachineBasicBlock::const_iterator I,
351f8af5cf6SDimitry Andric               MachineBasicBlock::const_iterator Beg) {
35258b69754SDimitry Andric   assert(I != Beg && "reached the top of the region, cannot decrement");
35358b69754SDimitry Andric   while (--I != Beg) {
354344a3780SDimitry Andric     if (!I->isDebugOrPseudoInstr())
35558b69754SDimitry Andric       break;
35658b69754SDimitry Andric   }
35758b69754SDimitry Andric   return I;
35858b69754SDimitry Andric }
35958b69754SDimitry Andric 
360f8af5cf6SDimitry Andric /// Non-const version.
361f8af5cf6SDimitry Andric static MachineBasicBlock::iterator
priorNonDebug(MachineBasicBlock::iterator I,MachineBasicBlock::const_iterator Beg)362f8af5cf6SDimitry Andric priorNonDebug(MachineBasicBlock::iterator I,
363f8af5cf6SDimitry Andric               MachineBasicBlock::const_iterator Beg) {
364b915e9e0SDimitry Andric   return priorNonDebug(MachineBasicBlock::const_iterator(I), Beg)
365b915e9e0SDimitry Andric       .getNonConstIterator();
366f8af5cf6SDimitry Andric }
367f8af5cf6SDimitry Andric 
36858b69754SDimitry Andric /// If this iterator is a debug value, increment until reaching the End or a
36958b69754SDimitry Andric /// non-debug instruction.
370f8af5cf6SDimitry Andric static MachineBasicBlock::const_iterator
nextIfDebug(MachineBasicBlock::const_iterator I,MachineBasicBlock::const_iterator End)371f8af5cf6SDimitry Andric nextIfDebug(MachineBasicBlock::const_iterator I,
372f8af5cf6SDimitry Andric             MachineBasicBlock::const_iterator End) {
37358b69754SDimitry Andric   for(; I != End; ++I) {
374344a3780SDimitry Andric     if (!I->isDebugOrPseudoInstr())
37558b69754SDimitry Andric       break;
37658b69754SDimitry Andric   }
37758b69754SDimitry Andric   return I;
37858b69754SDimitry Andric }
37958b69754SDimitry Andric 
380f8af5cf6SDimitry Andric /// Non-const version.
381f8af5cf6SDimitry Andric static MachineBasicBlock::iterator
nextIfDebug(MachineBasicBlock::iterator I,MachineBasicBlock::const_iterator End)382f8af5cf6SDimitry Andric nextIfDebug(MachineBasicBlock::iterator I,
383f8af5cf6SDimitry Andric             MachineBasicBlock::const_iterator End) {
384b915e9e0SDimitry Andric   return nextIfDebug(MachineBasicBlock::const_iterator(I), End)
385b915e9e0SDimitry Andric       .getNonConstIterator();
386f8af5cf6SDimitry Andric }
387f8af5cf6SDimitry Andric 
388f8af5cf6SDimitry Andric /// Instantiate a ScheduleDAGInstrs that will be owned by the caller.
createMachineScheduler()389f8af5cf6SDimitry Andric ScheduleDAGInstrs *MachineScheduler::createMachineScheduler() {
390f8af5cf6SDimitry Andric   // Select the scheduler, or set the default.
391f8af5cf6SDimitry Andric   MachineSchedRegistry::ScheduleDAGCtor Ctor = MachineSchedOpt;
392f8af5cf6SDimitry Andric   if (Ctor != useDefaultMachineSched)
393f8af5cf6SDimitry Andric     return Ctor(this);
394f8af5cf6SDimitry Andric 
395f8af5cf6SDimitry Andric   // Get the default scheduler set by the target for this function.
396f8af5cf6SDimitry Andric   ScheduleDAGInstrs *Scheduler = PassConfig->createMachineScheduler(this);
397f8af5cf6SDimitry Andric   if (Scheduler)
398f8af5cf6SDimitry Andric     return Scheduler;
399f8af5cf6SDimitry Andric 
400f8af5cf6SDimitry Andric   // Default to GenericScheduler.
4015ca98fd9SDimitry Andric   return createGenericSchedLive(this);
4025ca98fd9SDimitry Andric }
4035ca98fd9SDimitry Andric 
4045ca98fd9SDimitry Andric /// Instantiate a ScheduleDAGInstrs for PostRA scheduling that will be owned by
4055ca98fd9SDimitry Andric /// the caller. We don't have a command line option to override the postRA
4065ca98fd9SDimitry Andric /// scheduler. The Target must configure it.
createPostMachineScheduler()4075ca98fd9SDimitry Andric ScheduleDAGInstrs *PostMachineScheduler::createPostMachineScheduler() {
4085ca98fd9SDimitry Andric   // Get the postRA scheduler set by the target for this function.
4095ca98fd9SDimitry Andric   ScheduleDAGInstrs *Scheduler = PassConfig->createPostMachineScheduler(this);
4105ca98fd9SDimitry Andric   if (Scheduler)
4115ca98fd9SDimitry Andric     return Scheduler;
4125ca98fd9SDimitry Andric 
4135ca98fd9SDimitry Andric   // Default to GenericScheduler.
4145ca98fd9SDimitry Andric   return createGenericSchedPostRA(this);
415f8af5cf6SDimitry Andric }
416f8af5cf6SDimitry Andric 
41763faed5bSDimitry Andric /// Top-level MachineScheduler pass driver.
41863faed5bSDimitry Andric ///
41963faed5bSDimitry Andric /// Visit blocks in function order. Divide each block into scheduling regions
42063faed5bSDimitry Andric /// and visit them bottom-up. Visiting regions bottom-up is not required, but is
42163faed5bSDimitry Andric /// consistent with the DAG builder, which traverses the interior of the
42263faed5bSDimitry Andric /// scheduling regions bottom-up.
42363faed5bSDimitry Andric ///
42463faed5bSDimitry Andric /// This design avoids exposing scheduling boundaries to the DAG builder,
42563faed5bSDimitry Andric /// simplifying the DAG builder's support for "special" target instructions.
42663faed5bSDimitry Andric /// At the same time the design allows target schedulers to operate across
427eb11fae6SDimitry Andric /// scheduling boundaries, for example to bundle the boundary instructions
42863faed5bSDimitry Andric /// without reordering them. This creates complexity, because the target
42963faed5bSDimitry Andric /// scheduler must update the RegionBegin and RegionEnd positions cached by
43063faed5bSDimitry Andric /// ScheduleDAGInstrs whenever adding or removing instructions. A much simpler
43163faed5bSDimitry Andric /// design would be to split blocks at scheduling boundaries, but LLVM has a
43263faed5bSDimitry Andric /// general bias against block splitting purely for implementation simplicity.
runOnMachineFunction(MachineFunction & mf)43363faed5bSDimitry Andric bool MachineScheduler::runOnMachineFunction(MachineFunction &mf) {
434044eb2f6SDimitry Andric   if (skipFunction(mf.getFunction()))
43501095a5dSDimitry Andric     return false;
43601095a5dSDimitry Andric 
4375a5ac124SDimitry Andric   if (EnableMachineSched.getNumOccurrences()) {
4385a5ac124SDimitry Andric     if (!EnableMachineSched)
4395a5ac124SDimitry Andric       return false;
4405a5ac124SDimitry Andric   } else if (!mf.getSubtarget().enableMachineScheduler())
4415a5ac124SDimitry Andric     return false;
4425a5ac124SDimitry Andric 
443eb11fae6SDimitry Andric   LLVM_DEBUG(dbgs() << "Before MISched:\n"; mf.print(dbgs()));
44458b69754SDimitry Andric 
44563faed5bSDimitry Andric   // Initialize the context of the pass.
44663faed5bSDimitry Andric   MF = &mf;
447ac9a064cSDimitry Andric   MLI = &getAnalysis<MachineLoopInfoWrapperPass>().getLI();
448ac9a064cSDimitry Andric   MDT = &getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree();
44963faed5bSDimitry Andric   PassConfig = &getAnalysis<TargetPassConfig>();
450dd58ef01SDimitry Andric   AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();
45163faed5bSDimitry Andric 
452ac9a064cSDimitry Andric   LIS = &getAnalysis<LiveIntervalsWrapperPass>().getLIS();
45363faed5bSDimitry Andric 
4544a16efa3SDimitry Andric   if (VerifyScheduling) {
455eb11fae6SDimitry Andric     LLVM_DEBUG(LIS->dump());
4564a16efa3SDimitry Andric     MF->verify(this, "Before machine scheduling.");
4574a16efa3SDimitry Andric   }
45858b69754SDimitry Andric   RegClassInfo->runOnMachineFunction(*MF);
45958b69754SDimitry Andric 
460f8af5cf6SDimitry Andric   // Instantiate the selected scheduler for this target, function, and
461f8af5cf6SDimitry Andric   // optimization level.
4625ca98fd9SDimitry Andric   std::unique_ptr<ScheduleDAGInstrs> Scheduler(createMachineScheduler());
463ac9a064cSDimitry Andric   ScheduleDAGMI::DumpDirection D;
464ac9a064cSDimitry Andric   if (ForceTopDown)
465ac9a064cSDimitry Andric     D = ScheduleDAGMI::DumpDirection::TopDown;
466ac9a064cSDimitry Andric   else if (ForceBottomUp)
467ac9a064cSDimitry Andric     D = ScheduleDAGMI::DumpDirection::BottomUp;
468ac9a064cSDimitry Andric   else
469ac9a064cSDimitry Andric     D = ScheduleDAGMI::DumpDirection::Bidirectional;
470ac9a064cSDimitry Andric   Scheduler->setDumpDirection(D);
471dd58ef01SDimitry Andric   scheduleRegions(*Scheduler, false);
4725ca98fd9SDimitry Andric 
473eb11fae6SDimitry Andric   LLVM_DEBUG(LIS->dump());
4745ca98fd9SDimitry Andric   if (VerifyScheduling)
4755ca98fd9SDimitry Andric     MF->verify(this, "After machine scheduling.");
4765ca98fd9SDimitry Andric   return true;
4775ca98fd9SDimitry Andric }
4785ca98fd9SDimitry Andric 
runOnMachineFunction(MachineFunction & mf)4795ca98fd9SDimitry Andric bool PostMachineScheduler::runOnMachineFunction(MachineFunction &mf) {
480044eb2f6SDimitry Andric   if (skipFunction(mf.getFunction()))
4815ca98fd9SDimitry Andric     return false;
4825ca98fd9SDimitry Andric 
48301095a5dSDimitry Andric   if (EnablePostRAMachineSched.getNumOccurrences()) {
48401095a5dSDimitry Andric     if (!EnablePostRAMachineSched)
48501095a5dSDimitry Andric       return false;
486706b4fc4SDimitry Andric   } else if (!mf.getSubtarget().enablePostRAMachineScheduler()) {
487eb11fae6SDimitry Andric     LLVM_DEBUG(dbgs() << "Subtarget disables post-MI-sched.\n");
4885ca98fd9SDimitry Andric     return false;
4895ca98fd9SDimitry Andric   }
490eb11fae6SDimitry Andric   LLVM_DEBUG(dbgs() << "Before post-MI-sched:\n"; mf.print(dbgs()));
4915ca98fd9SDimitry Andric 
4925ca98fd9SDimitry Andric   // Initialize the context of the pass.
4935ca98fd9SDimitry Andric   MF = &mf;
494ac9a064cSDimitry Andric   MLI = &getAnalysis<MachineLoopInfoWrapperPass>().getLI();
4955ca98fd9SDimitry Andric   PassConfig = &getAnalysis<TargetPassConfig>();
496706b4fc4SDimitry Andric   AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();
4975ca98fd9SDimitry Andric 
4985ca98fd9SDimitry Andric   if (VerifyScheduling)
4995ca98fd9SDimitry Andric     MF->verify(this, "Before post machine scheduling.");
5005ca98fd9SDimitry Andric 
5015ca98fd9SDimitry Andric   // Instantiate the selected scheduler for this target, function, and
5025ca98fd9SDimitry Andric   // optimization level.
5035ca98fd9SDimitry Andric   std::unique_ptr<ScheduleDAGInstrs> Scheduler(createPostMachineScheduler());
504ac9a064cSDimitry Andric   ScheduleDAGMI::DumpDirection D;
505ac9a064cSDimitry Andric   if (PostRADirection == MISchedPostRASched::TopDown)
506ac9a064cSDimitry Andric     D = ScheduleDAGMI::DumpDirection::TopDown;
507ac9a064cSDimitry Andric   else if (PostRADirection == MISchedPostRASched::BottomUp)
508ac9a064cSDimitry Andric     D = ScheduleDAGMI::DumpDirection::BottomUp;
509ac9a064cSDimitry Andric   else
510ac9a064cSDimitry Andric     D = ScheduleDAGMI::DumpDirection::Bidirectional;
511ac9a064cSDimitry Andric   Scheduler->setDumpDirection(D);
512dd58ef01SDimitry Andric   scheduleRegions(*Scheduler, true);
5135ca98fd9SDimitry Andric 
5145ca98fd9SDimitry Andric   if (VerifyScheduling)
5155ca98fd9SDimitry Andric     MF->verify(this, "After post machine scheduling.");
5165ca98fd9SDimitry Andric   return true;
5175ca98fd9SDimitry Andric }
5185ca98fd9SDimitry Andric 
5195ca98fd9SDimitry Andric /// Return true of the given instruction should not be included in a scheduling
5205ca98fd9SDimitry Andric /// region.
5215ca98fd9SDimitry Andric ///
5225ca98fd9SDimitry Andric /// MachineScheduler does not currently support scheduling across calls. To
5235ca98fd9SDimitry Andric /// handle calls, the DAG builder needs to be modified to create register
5245ca98fd9SDimitry Andric /// anti/output dependencies on the registers clobbered by the call's regmask
5255ca98fd9SDimitry Andric /// operand. In PreRA scheduling, the stack pointer adjustment already prevents
5265ca98fd9SDimitry Andric /// scheduling across calls. In PostRA scheduling, we need the isCall to enforce
5275ca98fd9SDimitry Andric /// the boundary, but there would be no benefit to postRA scheduling across
5285ca98fd9SDimitry Andric /// calls this late anyway.
isSchedBoundary(MachineBasicBlock::iterator MI,MachineBasicBlock * MBB,MachineFunction * MF,const TargetInstrInfo * TII)5295ca98fd9SDimitry Andric static bool isSchedBoundary(MachineBasicBlock::iterator MI,
5305ca98fd9SDimitry Andric                             MachineBasicBlock *MBB,
5315ca98fd9SDimitry Andric                             MachineFunction *MF,
532dd58ef01SDimitry Andric                             const TargetInstrInfo *TII) {
53301095a5dSDimitry Andric   return MI->isCall() || TII->isSchedulingBoundary(*MI, MBB, *MF);
5345ca98fd9SDimitry Andric }
5355ca98fd9SDimitry Andric 
536044eb2f6SDimitry Andric /// A region of an MBB for scheduling.
537044eb2f6SDimitry Andric namespace {
538044eb2f6SDimitry Andric struct SchedRegion {
539044eb2f6SDimitry Andric   /// RegionBegin is the first instruction in the scheduling region, and
540044eb2f6SDimitry Andric   /// RegionEnd is either MBB->end() or the scheduling boundary after the
541044eb2f6SDimitry Andric   /// last instruction in the scheduling region. These iterators cannot refer
542044eb2f6SDimitry Andric   /// to instructions outside of the identified scheduling region because
543044eb2f6SDimitry Andric   /// those may be reordered before scheduling this region.
544044eb2f6SDimitry Andric   MachineBasicBlock::iterator RegionBegin;
545044eb2f6SDimitry Andric   MachineBasicBlock::iterator RegionEnd;
546044eb2f6SDimitry Andric   unsigned NumRegionInstrs;
547044eb2f6SDimitry Andric 
SchedRegion__anon233174dd0211::SchedRegion548044eb2f6SDimitry Andric   SchedRegion(MachineBasicBlock::iterator B, MachineBasicBlock::iterator E,
549044eb2f6SDimitry Andric               unsigned N) :
550044eb2f6SDimitry Andric     RegionBegin(B), RegionEnd(E), NumRegionInstrs(N) {}
551044eb2f6SDimitry Andric };
552044eb2f6SDimitry Andric } // end anonymous namespace
553044eb2f6SDimitry Andric 
554044eb2f6SDimitry Andric using MBBRegionsVector = SmallVector<SchedRegion, 16>;
555044eb2f6SDimitry Andric 
556044eb2f6SDimitry Andric static void
getSchedRegions(MachineBasicBlock * MBB,MBBRegionsVector & Regions,bool RegionsTopDown)557044eb2f6SDimitry Andric getSchedRegions(MachineBasicBlock *MBB,
558044eb2f6SDimitry Andric                 MBBRegionsVector &Regions,
559044eb2f6SDimitry Andric                 bool RegionsTopDown) {
560044eb2f6SDimitry Andric   MachineFunction *MF = MBB->getParent();
561044eb2f6SDimitry Andric   const TargetInstrInfo *TII = MF->getSubtarget().getInstrInfo();
562044eb2f6SDimitry Andric 
563044eb2f6SDimitry Andric   MachineBasicBlock::iterator I = nullptr;
564044eb2f6SDimitry Andric   for(MachineBasicBlock::iterator RegionEnd = MBB->end();
565044eb2f6SDimitry Andric       RegionEnd != MBB->begin(); RegionEnd = I) {
566044eb2f6SDimitry Andric 
567044eb2f6SDimitry Andric     // Avoid decrementing RegionEnd for blocks with no terminator.
568044eb2f6SDimitry Andric     if (RegionEnd != MBB->end() ||
569044eb2f6SDimitry Andric         isSchedBoundary(&*std::prev(RegionEnd), &*MBB, MF, TII)) {
570044eb2f6SDimitry Andric       --RegionEnd;
571044eb2f6SDimitry Andric     }
572044eb2f6SDimitry Andric 
573044eb2f6SDimitry Andric     // The next region starts above the previous region. Look backward in the
574044eb2f6SDimitry Andric     // instruction stream until we find the nearest boundary.
575044eb2f6SDimitry Andric     unsigned NumRegionInstrs = 0;
576044eb2f6SDimitry Andric     I = RegionEnd;
577044eb2f6SDimitry Andric     for (;I != MBB->begin(); --I) {
578044eb2f6SDimitry Andric       MachineInstr &MI = *std::prev(I);
579044eb2f6SDimitry Andric       if (isSchedBoundary(&MI, &*MBB, MF, TII))
580044eb2f6SDimitry Andric         break;
581344a3780SDimitry Andric       if (!MI.isDebugOrPseudoInstr()) {
582044eb2f6SDimitry Andric         // MBB::size() uses instr_iterator to count. Here we need a bundle to
583044eb2f6SDimitry Andric         // count as a single instruction.
584044eb2f6SDimitry Andric         ++NumRegionInstrs;
585044eb2f6SDimitry Andric       }
586e6d15924SDimitry Andric     }
587044eb2f6SDimitry Andric 
588e6d15924SDimitry Andric     // It's possible we found a scheduling region that only has debug
589e6d15924SDimitry Andric     // instructions. Don't bother scheduling these.
590e6d15924SDimitry Andric     if (NumRegionInstrs != 0)
591044eb2f6SDimitry Andric       Regions.push_back(SchedRegion(I, RegionEnd, NumRegionInstrs));
592044eb2f6SDimitry Andric   }
593044eb2f6SDimitry Andric 
594044eb2f6SDimitry Andric   if (RegionsTopDown)
595044eb2f6SDimitry Andric     std::reverse(Regions.begin(), Regions.end());
596044eb2f6SDimitry Andric }
597044eb2f6SDimitry Andric 
5985ca98fd9SDimitry Andric /// Main driver for both MachineScheduler and PostMachineScheduler.
scheduleRegions(ScheduleDAGInstrs & Scheduler,bool FixKillFlags)599dd58ef01SDimitry Andric void MachineSchedulerBase::scheduleRegions(ScheduleDAGInstrs &Scheduler,
600dd58ef01SDimitry Andric                                            bool FixKillFlags) {
60163faed5bSDimitry Andric   // Visit all machine basic blocks.
60258b69754SDimitry Andric   //
60358b69754SDimitry Andric   // TODO: Visit blocks in global postorder or postorder within the bottom-up
60458b69754SDimitry Andric   // loop tree. Then we can optionally compute global RegPressure.
60563faed5bSDimitry Andric   for (MachineFunction::iterator MBB = MF->begin(), MBBEnd = MF->end();
60663faed5bSDimitry Andric        MBB != MBBEnd; ++MBB) {
60763faed5bSDimitry Andric 
608dd58ef01SDimitry Andric     Scheduler.startBlock(&*MBB);
6095ca98fd9SDimitry Andric 
6105ca98fd9SDimitry Andric #ifndef NDEBUG
6115ca98fd9SDimitry Andric     if (SchedOnlyFunc.getNumOccurrences() && SchedOnlyFunc != MF->getName())
6125ca98fd9SDimitry Andric       continue;
6135ca98fd9SDimitry Andric     if (SchedOnlyBlock.getNumOccurrences()
6145ca98fd9SDimitry Andric         && (int)SchedOnlyBlock != MBB->getNumber())
6155ca98fd9SDimitry Andric       continue;
6165ca98fd9SDimitry Andric #endif
61763faed5bSDimitry Andric 
618044eb2f6SDimitry Andric     // Break the block into scheduling regions [I, RegionEnd). RegionEnd
619044eb2f6SDimitry Andric     // points to the scheduling boundary at the bottom of the region. The DAG
620044eb2f6SDimitry Andric     // does not include RegionEnd, but the region does (i.e. the next
621044eb2f6SDimitry Andric     // RegionEnd is above the previous RegionBegin). If the current block has
622044eb2f6SDimitry Andric     // no terminator then RegionEnd == MBB->end() for the bottom region.
623044eb2f6SDimitry Andric     //
624044eb2f6SDimitry Andric     // All the regions of MBB are first found and stored in MBBRegions, which
625044eb2f6SDimitry Andric     // will be processed (MBB) top-down if initialized with true.
62663faed5bSDimitry Andric     //
62763faed5bSDimitry Andric     // The Scheduler may insert instructions during either schedule() or
62863faed5bSDimitry Andric     // exitRegion(), even for empty regions. So the local iterators 'I' and
629044eb2f6SDimitry Andric     // 'RegionEnd' are invalid across these calls. Instructions must not be
630044eb2f6SDimitry Andric     // added to other regions than the current one without updating MBBRegions.
63158b69754SDimitry Andric 
632044eb2f6SDimitry Andric     MBBRegionsVector MBBRegions;
633044eb2f6SDimitry Andric     getSchedRegions(&*MBB, MBBRegions, Scheduler.doMBBSchedRegionsTopDown());
63477fc4c14SDimitry Andric     for (const SchedRegion &R : MBBRegions) {
63577fc4c14SDimitry Andric       MachineBasicBlock::iterator I = R.RegionBegin;
63677fc4c14SDimitry Andric       MachineBasicBlock::iterator RegionEnd = R.RegionEnd;
63777fc4c14SDimitry Andric       unsigned NumRegionInstrs = R.NumRegionInstrs;
63863faed5bSDimitry Andric 
63963faed5bSDimitry Andric       // Notify the scheduler of the region, even if we may skip scheduling
64063faed5bSDimitry Andric       // it. Perhaps it still needs to be bundled.
641dd58ef01SDimitry Andric       Scheduler.enterRegion(&*MBB, I, RegionEnd, NumRegionInstrs);
64263faed5bSDimitry Andric 
64363faed5bSDimitry Andric       // Skip empty scheduling regions (0 or 1 schedulable instructions).
6445ca98fd9SDimitry Andric       if (I == RegionEnd || I == std::prev(RegionEnd)) {
64563faed5bSDimitry Andric         // Close the current region. Bundle the terminator if needed.
64663faed5bSDimitry Andric         // This invalidates 'RegionEnd' and 'I'.
6475ca98fd9SDimitry Andric         Scheduler.exitRegion();
64863faed5bSDimitry Andric         continue;
64963faed5bSDimitry Andric       }
650eb11fae6SDimitry Andric       LLVM_DEBUG(dbgs() << "********** MI Scheduling **********\n");
651eb11fae6SDimitry Andric       LLVM_DEBUG(dbgs() << MF->getName() << ":" << printMBBReference(*MBB)
652eb11fae6SDimitry Andric                         << " " << MBB->getName() << "\n  From: " << *I
653eb11fae6SDimitry Andric                         << "    To: ";
65463faed5bSDimitry Andric                  if (RegionEnd != MBB->end()) dbgs() << *RegionEnd;
655c0981da4SDimitry Andric                  else dbgs() << "End\n";
65601095a5dSDimitry Andric                  dbgs() << " RegionInstrs: " << NumRegionInstrs << '\n');
65767c32a98SDimitry Andric       if (DumpCriticalPathLength) {
65867c32a98SDimitry Andric         errs() << MF->getName();
659044eb2f6SDimitry Andric         errs() << ":%bb. " << MBB->getNumber();
66067c32a98SDimitry Andric         errs() << " " << MBB->getName() << " \n";
66167c32a98SDimitry Andric       }
66263faed5bSDimitry Andric 
66363faed5bSDimitry Andric       // Schedule a region: possibly reorder instructions.
664044eb2f6SDimitry Andric       // This invalidates the original region iterators.
6655ca98fd9SDimitry Andric       Scheduler.schedule();
66663faed5bSDimitry Andric 
66763faed5bSDimitry Andric       // Close the current region.
6685ca98fd9SDimitry Andric       Scheduler.exitRegion();
66963faed5bSDimitry Andric     }
6705ca98fd9SDimitry Andric     Scheduler.finishBlock();
6715ca98fd9SDimitry Andric     // FIXME: Ideally, no further passes should rely on kill flags. However,
672dd58ef01SDimitry Andric     // thumb2 size reduction is currently an exception, so the PostMIScheduler
673dd58ef01SDimitry Andric     // needs to do this.
674dd58ef01SDimitry Andric     if (FixKillFlags)
675ab44ce3dSDimitry Andric       Scheduler.fixupKills(*MBB);
6765ca98fd9SDimitry Andric   }
6775ca98fd9SDimitry Andric   Scheduler.finalizeSchedule();
67863faed5bSDimitry Andric }
67963faed5bSDimitry Andric 
print(raw_ostream & O,const Module * m) const6805ca98fd9SDimitry Andric void MachineSchedulerBase::print(raw_ostream &O, const Module* m) const {
68163faed5bSDimitry Andric   // unimplemented
68263faed5bSDimitry Andric }
68363faed5bSDimitry Andric 
68471d5a254SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
dump() const68508bbd35aSDimitry Andric LLVM_DUMP_METHOD void ReadyQueue::dump() const {
686dd58ef01SDimitry Andric   dbgs() << "Queue " << Name << ": ";
68708bbd35aSDimitry Andric   for (const SUnit *SU : Queue)
68808bbd35aSDimitry Andric     dbgs() << SU->NodeNum << " ";
689522600a2SDimitry Andric   dbgs() << "\n";
690522600a2SDimitry Andric }
69171d5a254SDimitry Andric #endif
69263faed5bSDimitry Andric 
69363faed5bSDimitry Andric //===----------------------------------------------------------------------===//
6945ca98fd9SDimitry Andric // ScheduleDAGMI - Basic machine instruction scheduling. This is
6955ca98fd9SDimitry Andric // independent of PreRA/PostRA scheduling and involves no extra book-keeping for
6965ca98fd9SDimitry Andric // virtual registers.
6975ca98fd9SDimitry Andric // ===----------------------------------------------------------------------===/
69863faed5bSDimitry Andric 
6995ca98fd9SDimitry Andric // Provide a vtable anchor.
70071d5a254SDimitry Andric ScheduleDAGMI::~ScheduleDAGMI() = default;
7014a16efa3SDimitry Andric 
70263faed5bSDimitry Andric /// ReleaseSucc - Decrement the NumPredsLeft count of a successor. When
70363faed5bSDimitry Andric /// NumPredsLeft reaches zero, release the successor node.
70458b69754SDimitry Andric ///
70558b69754SDimitry Andric /// FIXME: Adjust SuccSU height based on MinLatency.
releaseSucc(SUnit * SU,SDep * SuccEdge)70663faed5bSDimitry Andric void ScheduleDAGMI::releaseSucc(SUnit *SU, SDep *SuccEdge) {
70763faed5bSDimitry Andric   SUnit *SuccSU = SuccEdge->getSUnit();
70863faed5bSDimitry Andric 
7094a16efa3SDimitry Andric   if (SuccEdge->isWeak()) {
7104a16efa3SDimitry Andric     --SuccSU->WeakPredsLeft;
7114a16efa3SDimitry Andric     if (SuccEdge->isCluster())
7124a16efa3SDimitry Andric       NextClusterSucc = SuccSU;
7134a16efa3SDimitry Andric     return;
7144a16efa3SDimitry Andric   }
71563faed5bSDimitry Andric #ifndef NDEBUG
71663faed5bSDimitry Andric   if (SuccSU->NumPredsLeft == 0) {
71763faed5bSDimitry Andric     dbgs() << "*** Scheduling failed! ***\n";
718d8e91e46SDimitry Andric     dumpNode(*SuccSU);
71963faed5bSDimitry Andric     dbgs() << " has been released too many times!\n";
7205ca98fd9SDimitry Andric     llvm_unreachable(nullptr);
72163faed5bSDimitry Andric   }
72263faed5bSDimitry Andric #endif
7235ca98fd9SDimitry Andric   // SU->TopReadyCycle was set to CurrCycle when it was scheduled. However,
7245ca98fd9SDimitry Andric   // CurrCycle may have advanced since then.
7255ca98fd9SDimitry Andric   if (SuccSU->TopReadyCycle < SU->TopReadyCycle + SuccEdge->getLatency())
7265ca98fd9SDimitry Andric     SuccSU->TopReadyCycle = SU->TopReadyCycle + SuccEdge->getLatency();
7275ca98fd9SDimitry Andric 
72863faed5bSDimitry Andric   --SuccSU->NumPredsLeft;
72963faed5bSDimitry Andric   if (SuccSU->NumPredsLeft == 0 && SuccSU != &ExitSU)
73063faed5bSDimitry Andric     SchedImpl->releaseTopNode(SuccSU);
73163faed5bSDimitry Andric }
73263faed5bSDimitry Andric 
73363faed5bSDimitry Andric /// releaseSuccessors - Call releaseSucc on each of SU's successors.
releaseSuccessors(SUnit * SU)73463faed5bSDimitry Andric void ScheduleDAGMI::releaseSuccessors(SUnit *SU) {
73508bbd35aSDimitry Andric   for (SDep &Succ : SU->Succs)
73608bbd35aSDimitry Andric     releaseSucc(SU, &Succ);
73763faed5bSDimitry Andric }
73863faed5bSDimitry Andric 
73963faed5bSDimitry Andric /// ReleasePred - Decrement the NumSuccsLeft count of a predecessor. When
74063faed5bSDimitry Andric /// NumSuccsLeft reaches zero, release the predecessor node.
74158b69754SDimitry Andric ///
74258b69754SDimitry Andric /// FIXME: Adjust PredSU height based on MinLatency.
releasePred(SUnit * SU,SDep * PredEdge)74363faed5bSDimitry Andric void ScheduleDAGMI::releasePred(SUnit *SU, SDep *PredEdge) {
74463faed5bSDimitry Andric   SUnit *PredSU = PredEdge->getSUnit();
74563faed5bSDimitry Andric 
7464a16efa3SDimitry Andric   if (PredEdge->isWeak()) {
7474a16efa3SDimitry Andric     --PredSU->WeakSuccsLeft;
7484a16efa3SDimitry Andric     if (PredEdge->isCluster())
7494a16efa3SDimitry Andric       NextClusterPred = PredSU;
7504a16efa3SDimitry Andric     return;
7514a16efa3SDimitry Andric   }
75263faed5bSDimitry Andric #ifndef NDEBUG
75363faed5bSDimitry Andric   if (PredSU->NumSuccsLeft == 0) {
75463faed5bSDimitry Andric     dbgs() << "*** Scheduling failed! ***\n";
755d8e91e46SDimitry Andric     dumpNode(*PredSU);
75663faed5bSDimitry Andric     dbgs() << " has been released too many times!\n";
7575ca98fd9SDimitry Andric     llvm_unreachable(nullptr);
75863faed5bSDimitry Andric   }
75963faed5bSDimitry Andric #endif
7605ca98fd9SDimitry Andric   // SU->BotReadyCycle was set to CurrCycle when it was scheduled. However,
7615ca98fd9SDimitry Andric   // CurrCycle may have advanced since then.
7625ca98fd9SDimitry Andric   if (PredSU->BotReadyCycle < SU->BotReadyCycle + PredEdge->getLatency())
7635ca98fd9SDimitry Andric     PredSU->BotReadyCycle = SU->BotReadyCycle + PredEdge->getLatency();
7645ca98fd9SDimitry Andric 
76563faed5bSDimitry Andric   --PredSU->NumSuccsLeft;
76663faed5bSDimitry Andric   if (PredSU->NumSuccsLeft == 0 && PredSU != &EntrySU)
76763faed5bSDimitry Andric     SchedImpl->releaseBottomNode(PredSU);
76863faed5bSDimitry Andric }
76963faed5bSDimitry Andric 
77063faed5bSDimitry Andric /// releasePredecessors - Call releasePred on each of SU's predecessors.
releasePredecessors(SUnit * SU)77163faed5bSDimitry Andric void ScheduleDAGMI::releasePredecessors(SUnit *SU) {
77208bbd35aSDimitry Andric   for (SDep &Pred : SU->Preds)
77308bbd35aSDimitry Andric     releasePred(SU, &Pred);
77463faed5bSDimitry Andric }
77563faed5bSDimitry Andric 
startBlock(MachineBasicBlock * bb)776044eb2f6SDimitry Andric void ScheduleDAGMI::startBlock(MachineBasicBlock *bb) {
777044eb2f6SDimitry Andric   ScheduleDAGInstrs::startBlock(bb);
778044eb2f6SDimitry Andric   SchedImpl->enterMBB(bb);
779044eb2f6SDimitry Andric }
780044eb2f6SDimitry Andric 
finishBlock()781044eb2f6SDimitry Andric void ScheduleDAGMI::finishBlock() {
782044eb2f6SDimitry Andric   SchedImpl->leaveMBB();
783044eb2f6SDimitry Andric   ScheduleDAGInstrs::finishBlock();
784044eb2f6SDimitry Andric }
785044eb2f6SDimitry Andric 
786312c0ed1SDimitry Andric /// enterRegion - Called back from PostMachineScheduler::runOnMachineFunction
787312c0ed1SDimitry Andric /// after crossing a scheduling boundary. [begin, end) includes all instructions
788312c0ed1SDimitry Andric /// in the region, including the boundary itself and single-instruction regions
7895ca98fd9SDimitry Andric /// that don't get scheduled.
enterRegion(MachineBasicBlock * bb,MachineBasicBlock::iterator begin,MachineBasicBlock::iterator end,unsigned regioninstrs)7905ca98fd9SDimitry Andric void ScheduleDAGMI::enterRegion(MachineBasicBlock *bb,
7915ca98fd9SDimitry Andric                                      MachineBasicBlock::iterator begin,
7925ca98fd9SDimitry Andric                                      MachineBasicBlock::iterator end,
7935ca98fd9SDimitry Andric                                      unsigned regioninstrs)
7945ca98fd9SDimitry Andric {
7955ca98fd9SDimitry Andric   ScheduleDAGInstrs::enterRegion(bb, begin, end, regioninstrs);
7965ca98fd9SDimitry Andric 
7975ca98fd9SDimitry Andric   SchedImpl->initPolicy(begin, end, regioninstrs);
7985ca98fd9SDimitry Andric }
7995ca98fd9SDimitry Andric 
80059d6cff9SDimitry Andric /// This is normally called from the main scheduler loop but may also be invoked
80159d6cff9SDimitry Andric /// by the scheduling strategy to perform additional code motion.
moveInstruction(MachineInstr * MI,MachineBasicBlock::iterator InsertPos)8025ca98fd9SDimitry Andric void ScheduleDAGMI::moveInstruction(
8035ca98fd9SDimitry Andric   MachineInstr *MI, MachineBasicBlock::iterator InsertPos) {
80458b69754SDimitry Andric   // Advance RegionBegin if the first instruction moves down.
80563faed5bSDimitry Andric   if (&*RegionBegin == MI)
80658b69754SDimitry Andric     ++RegionBegin;
80758b69754SDimitry Andric 
80858b69754SDimitry Andric   // Update the instruction stream.
80963faed5bSDimitry Andric   BB->splice(InsertPos, BB, MI);
81058b69754SDimitry Andric 
81158b69754SDimitry Andric   // Update LiveIntervals
8125ca98fd9SDimitry Andric   if (LIS)
81301095a5dSDimitry Andric     LIS->handleMove(*MI, /*UpdateFlags=*/true);
81458b69754SDimitry Andric 
81558b69754SDimitry Andric   // Recede RegionBegin if an instruction moves above the first.
81663faed5bSDimitry Andric   if (RegionBegin == InsertPos)
81763faed5bSDimitry Andric     RegionBegin = MI;
81863faed5bSDimitry Andric }
81963faed5bSDimitry Andric 
checkSchedLimit()82063faed5bSDimitry Andric bool ScheduleDAGMI::checkSchedLimit() {
821e3b55780SDimitry Andric #if LLVM_ENABLE_ABI_BREAKING_CHECKS && !defined(NDEBUG)
82263faed5bSDimitry Andric   if (NumInstrsScheduled == MISchedCutoff && MISchedCutoff != ~0U) {
82363faed5bSDimitry Andric     CurrentTop = CurrentBottom;
82463faed5bSDimitry Andric     return false;
82563faed5bSDimitry Andric   }
82663faed5bSDimitry Andric   ++NumInstrsScheduled;
82763faed5bSDimitry Andric #endif
82863faed5bSDimitry Andric   return true;
82963faed5bSDimitry Andric }
83063faed5bSDimitry Andric 
8315ca98fd9SDimitry Andric /// Per-region scheduling driver, called back from
832312c0ed1SDimitry Andric /// PostMachineScheduler::runOnMachineFunction. This is a simplified driver
833312c0ed1SDimitry Andric /// that does not consider liveness or register pressure. It is useful for
834312c0ed1SDimitry Andric /// PostRA scheduling and potentially other custom schedulers.
schedule()8355ca98fd9SDimitry Andric void ScheduleDAGMI::schedule() {
836eb11fae6SDimitry Andric   LLVM_DEBUG(dbgs() << "ScheduleDAGMI::schedule starting\n");
837eb11fae6SDimitry Andric   LLVM_DEBUG(SchedImpl->dumpPolicy());
838dd58ef01SDimitry Andric 
8395ca98fd9SDimitry Andric   // Build the DAG.
8405ca98fd9SDimitry Andric   buildSchedGraph(AA);
8415ca98fd9SDimitry Andric 
8427fa27ce4SDimitry Andric   postProcessDAG();
8435ca98fd9SDimitry Andric 
8445ca98fd9SDimitry Andric   SmallVector<SUnit*, 8> TopRoots, BotRoots;
8455ca98fd9SDimitry Andric   findRootsAndBiasEdges(TopRoots, BotRoots);
8465ca98fd9SDimitry Andric 
847d8e91e46SDimitry Andric   LLVM_DEBUG(dump());
848d8e91e46SDimitry Andric   if (PrintDAGs) dump();
849eb11fae6SDimitry Andric   if (ViewMISchedDAGs) viewGraph();
850eb11fae6SDimitry Andric 
8515ca98fd9SDimitry Andric   // Initialize the strategy before modifying the DAG.
8525ca98fd9SDimitry Andric   // This may initialize a DFSResult to be used for queue priority.
8535ca98fd9SDimitry Andric   SchedImpl->initialize(this);
8545ca98fd9SDimitry Andric 
8555ca98fd9SDimitry Andric   // Initialize ready queues now that the DAG and priority data are finalized.
8565ca98fd9SDimitry Andric   initQueues(TopRoots, BotRoots);
8575ca98fd9SDimitry Andric 
8585ca98fd9SDimitry Andric   bool IsTopNode = false;
859dd58ef01SDimitry Andric   while (true) {
860eb11fae6SDimitry Andric     LLVM_DEBUG(dbgs() << "** ScheduleDAGMI::schedule picking next node\n");
861dd58ef01SDimitry Andric     SUnit *SU = SchedImpl->pickNode(IsTopNode);
862dd58ef01SDimitry Andric     if (!SU) break;
863dd58ef01SDimitry Andric 
8645ca98fd9SDimitry Andric     assert(!SU->isScheduled && "Node already scheduled");
8655ca98fd9SDimitry Andric     if (!checkSchedLimit())
8665ca98fd9SDimitry Andric       break;
8675ca98fd9SDimitry Andric 
8685ca98fd9SDimitry Andric     MachineInstr *MI = SU->getInstr();
8695ca98fd9SDimitry Andric     if (IsTopNode) {
8705ca98fd9SDimitry Andric       assert(SU->isTopReady() && "node still has unscheduled dependencies");
8715ca98fd9SDimitry Andric       if (&*CurrentTop == MI)
8725ca98fd9SDimitry Andric         CurrentTop = nextIfDebug(++CurrentTop, CurrentBottom);
8735ca98fd9SDimitry Andric       else
8745ca98fd9SDimitry Andric         moveInstruction(MI, CurrentTop);
87501095a5dSDimitry Andric     } else {
8765ca98fd9SDimitry Andric       assert(SU->isBottomReady() && "node still has unscheduled dependencies");
8775ca98fd9SDimitry Andric       MachineBasicBlock::iterator priorII =
8785ca98fd9SDimitry Andric         priorNonDebug(CurrentBottom, CurrentTop);
8795ca98fd9SDimitry Andric       if (&*priorII == MI)
8805ca98fd9SDimitry Andric         CurrentBottom = priorII;
8815ca98fd9SDimitry Andric       else {
8825ca98fd9SDimitry Andric         if (&*CurrentTop == MI)
8835ca98fd9SDimitry Andric           CurrentTop = nextIfDebug(++CurrentTop, priorII);
8845ca98fd9SDimitry Andric         moveInstruction(MI, CurrentBottom);
8855ca98fd9SDimitry Andric         CurrentBottom = MI;
8865ca98fd9SDimitry Andric       }
8875ca98fd9SDimitry Andric     }
8885ca98fd9SDimitry Andric     // Notify the scheduling strategy before updating the DAG.
8895ca98fd9SDimitry Andric     // This sets the scheduled node's ReadyCycle to CurrCycle. When updateQueues
8905ca98fd9SDimitry Andric     // runs, it can then use the accurate ReadyCycle time to determine whether
8915ca98fd9SDimitry Andric     // newly released nodes can move to the readyQ.
8925ca98fd9SDimitry Andric     SchedImpl->schedNode(SU, IsTopNode);
8935ca98fd9SDimitry Andric 
8945ca98fd9SDimitry Andric     updateQueues(SU, IsTopNode);
8955ca98fd9SDimitry Andric   }
8965ca98fd9SDimitry Andric   assert(CurrentTop == CurrentBottom && "Nonempty unscheduled zone.");
8975ca98fd9SDimitry Andric 
8985ca98fd9SDimitry Andric   placeDebugValues();
8995ca98fd9SDimitry Andric 
900eb11fae6SDimitry Andric   LLVM_DEBUG({
901044eb2f6SDimitry Andric     dbgs() << "*** Final schedule for "
902044eb2f6SDimitry Andric            << printMBBReference(*begin()->getParent()) << " ***\n";
9035ca98fd9SDimitry Andric     dumpSchedule();
9045ca98fd9SDimitry Andric     dbgs() << '\n';
9055ca98fd9SDimitry Andric   });
9065ca98fd9SDimitry Andric }
9075ca98fd9SDimitry Andric 
9085ca98fd9SDimitry Andric /// Apply each ScheduleDAGMutation step in order.
postProcessDAG()9097fa27ce4SDimitry Andric void ScheduleDAGMI::postProcessDAG() {
91008bbd35aSDimitry Andric   for (auto &m : Mutations)
91108bbd35aSDimitry Andric     m->apply(this);
9125ca98fd9SDimitry Andric }
9135ca98fd9SDimitry Andric 
9145ca98fd9SDimitry Andric void ScheduleDAGMI::
findRootsAndBiasEdges(SmallVectorImpl<SUnit * > & TopRoots,SmallVectorImpl<SUnit * > & BotRoots)9155ca98fd9SDimitry Andric findRootsAndBiasEdges(SmallVectorImpl<SUnit*> &TopRoots,
9165ca98fd9SDimitry Andric                       SmallVectorImpl<SUnit*> &BotRoots) {
91708bbd35aSDimitry Andric   for (SUnit &SU : SUnits) {
91808bbd35aSDimitry Andric     assert(!SU.isBoundaryNode() && "Boundary node should not be in SUnits");
9195ca98fd9SDimitry Andric 
9205ca98fd9SDimitry Andric     // Order predecessors so DFSResult follows the critical path.
92108bbd35aSDimitry Andric     SU.biasCriticalPath();
9225ca98fd9SDimitry Andric 
9235ca98fd9SDimitry Andric     // A SUnit is ready to top schedule if it has no predecessors.
92408bbd35aSDimitry Andric     if (!SU.NumPredsLeft)
92508bbd35aSDimitry Andric       TopRoots.push_back(&SU);
9265ca98fd9SDimitry Andric     // A SUnit is ready to bottom schedule if it has no successors.
92708bbd35aSDimitry Andric     if (!SU.NumSuccsLeft)
92808bbd35aSDimitry Andric       BotRoots.push_back(&SU);
9295ca98fd9SDimitry Andric   }
9305ca98fd9SDimitry Andric   ExitSU.biasCriticalPath();
9315ca98fd9SDimitry Andric }
9325ca98fd9SDimitry Andric 
9335ca98fd9SDimitry Andric /// Identify DAG roots and setup scheduler queues.
initQueues(ArrayRef<SUnit * > TopRoots,ArrayRef<SUnit * > BotRoots)9345ca98fd9SDimitry Andric void ScheduleDAGMI::initQueues(ArrayRef<SUnit*> TopRoots,
9355ca98fd9SDimitry Andric                                ArrayRef<SUnit*> BotRoots) {
9365ca98fd9SDimitry Andric   NextClusterSucc = nullptr;
9375ca98fd9SDimitry Andric   NextClusterPred = nullptr;
9385ca98fd9SDimitry Andric 
9395ca98fd9SDimitry Andric   // Release all DAG roots for scheduling, not including EntrySU/ExitSU.
9405ca98fd9SDimitry Andric   //
9415ca98fd9SDimitry Andric   // Nodes with unreleased weak edges can still be roots.
9425ca98fd9SDimitry Andric   // Release top roots in forward order.
94308bbd35aSDimitry Andric   for (SUnit *SU : TopRoots)
94408bbd35aSDimitry Andric     SchedImpl->releaseTopNode(SU);
94508bbd35aSDimitry Andric 
9465ca98fd9SDimitry Andric   // Release bottom roots in reverse order so the higher priority nodes appear
9475ca98fd9SDimitry Andric   // first. This is more natural and slightly more efficient.
9485ca98fd9SDimitry Andric   for (SmallVectorImpl<SUnit*>::const_reverse_iterator
9495ca98fd9SDimitry Andric          I = BotRoots.rbegin(), E = BotRoots.rend(); I != E; ++I) {
9505ca98fd9SDimitry Andric     SchedImpl->releaseBottomNode(*I);
9515ca98fd9SDimitry Andric   }
9525ca98fd9SDimitry Andric 
9535ca98fd9SDimitry Andric   releaseSuccessors(&EntrySU);
9545ca98fd9SDimitry Andric   releasePredecessors(&ExitSU);
9555ca98fd9SDimitry Andric 
9565ca98fd9SDimitry Andric   SchedImpl->registerRoots();
9575ca98fd9SDimitry Andric 
9585ca98fd9SDimitry Andric   // Advance past initial DebugValues.
9595ca98fd9SDimitry Andric   CurrentTop = nextIfDebug(RegionBegin, RegionEnd);
9605ca98fd9SDimitry Andric   CurrentBottom = RegionEnd;
9615ca98fd9SDimitry Andric }
9625ca98fd9SDimitry Andric 
9635ca98fd9SDimitry Andric /// Update scheduler queues after scheduling an instruction.
updateQueues(SUnit * SU,bool IsTopNode)9645ca98fd9SDimitry Andric void ScheduleDAGMI::updateQueues(SUnit *SU, bool IsTopNode) {
9655ca98fd9SDimitry Andric   // Release dependent instructions for scheduling.
9665ca98fd9SDimitry Andric   if (IsTopNode)
9675ca98fd9SDimitry Andric     releaseSuccessors(SU);
9685ca98fd9SDimitry Andric   else
9695ca98fd9SDimitry Andric     releasePredecessors(SU);
9705ca98fd9SDimitry Andric 
9715ca98fd9SDimitry Andric   SU->isScheduled = true;
9725ca98fd9SDimitry Andric }
9735ca98fd9SDimitry Andric 
9745ca98fd9SDimitry Andric /// Reinsert any remaining debug_values, just like the PostRA scheduler.
placeDebugValues()9755ca98fd9SDimitry Andric void ScheduleDAGMI::placeDebugValues() {
9765ca98fd9SDimitry Andric   // If first instruction was a DBG_VALUE then put it back.
9775ca98fd9SDimitry Andric   if (FirstDbgValue) {
9785ca98fd9SDimitry Andric     BB->splice(RegionBegin, BB, FirstDbgValue);
9795ca98fd9SDimitry Andric     RegionBegin = FirstDbgValue;
9805ca98fd9SDimitry Andric   }
9815ca98fd9SDimitry Andric 
9825ca98fd9SDimitry Andric   for (std::vector<std::pair<MachineInstr *, MachineInstr *>>::iterator
9835ca98fd9SDimitry Andric          DI = DbgValues.end(), DE = DbgValues.begin(); DI != DE; --DI) {
9845ca98fd9SDimitry Andric     std::pair<MachineInstr *, MachineInstr *> P = *std::prev(DI);
9855ca98fd9SDimitry Andric     MachineInstr *DbgValue = P.first;
9865ca98fd9SDimitry Andric     MachineBasicBlock::iterator OrigPrevMI = P.second;
9875ca98fd9SDimitry Andric     if (&*RegionBegin == DbgValue)
9885ca98fd9SDimitry Andric       ++RegionBegin;
989145449b1SDimitry Andric     BB->splice(std::next(OrigPrevMI), BB, DbgValue);
990145449b1SDimitry Andric     if (RegionEnd != BB->end() && OrigPrevMI == &*RegionEnd)
9915ca98fd9SDimitry Andric       RegionEnd = DbgValue;
9925ca98fd9SDimitry Andric   }
9935ca98fd9SDimitry Andric }
9945ca98fd9SDimitry Andric 
9955ca98fd9SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
9967fa27ce4SDimitry Andric static const char *scheduleTableLegend = "  i: issue\n  x: resource booked";
9977fa27ce4SDimitry Andric 
dumpScheduleTraceTopDown() const9987fa27ce4SDimitry Andric LLVM_DUMP_METHOD void ScheduleDAGMI::dumpScheduleTraceTopDown() const {
9997fa27ce4SDimitry Andric   // Bail off when there is no schedule model to query.
10007fa27ce4SDimitry Andric   if (!SchedModel.hasInstrSchedModel())
10017fa27ce4SDimitry Andric     return;
10027fa27ce4SDimitry Andric 
10037fa27ce4SDimitry Andric   //  Nothing to show if there is no or just one instruction.
10047fa27ce4SDimitry Andric   if (BB->size() < 2)
10057fa27ce4SDimitry Andric     return;
10067fa27ce4SDimitry Andric 
10077fa27ce4SDimitry Andric   dbgs() << " * Schedule table (TopDown):\n";
10087fa27ce4SDimitry Andric   dbgs() << scheduleTableLegend << "\n";
10097fa27ce4SDimitry Andric   const unsigned FirstCycle = getSUnit(&*(std::begin(*this)))->TopReadyCycle;
10107fa27ce4SDimitry Andric   unsigned LastCycle = getSUnit(&*(std::prev(std::end(*this))))->TopReadyCycle;
10117fa27ce4SDimitry Andric   for (MachineInstr &MI : *this) {
10127fa27ce4SDimitry Andric     SUnit *SU = getSUnit(&MI);
10137fa27ce4SDimitry Andric     if (!SU)
10147fa27ce4SDimitry Andric       continue;
10157fa27ce4SDimitry Andric     const MCSchedClassDesc *SC = getSchedClass(SU);
10167fa27ce4SDimitry Andric     for (TargetSchedModel::ProcResIter PI = SchedModel.getWriteProcResBegin(SC),
10177fa27ce4SDimitry Andric                                        PE = SchedModel.getWriteProcResEnd(SC);
10187fa27ce4SDimitry Andric          PI != PE; ++PI) {
1019b1c73532SDimitry Andric       if (SU->TopReadyCycle + PI->ReleaseAtCycle - 1 > LastCycle)
1020b1c73532SDimitry Andric         LastCycle = SU->TopReadyCycle + PI->ReleaseAtCycle - 1;
10217fa27ce4SDimitry Andric     }
10227fa27ce4SDimitry Andric   }
10237fa27ce4SDimitry Andric   // Print the header with the cycles
10247fa27ce4SDimitry Andric   dbgs() << llvm::left_justify("Cycle", HeaderColWidth);
10257fa27ce4SDimitry Andric   for (unsigned C = FirstCycle; C <= LastCycle; ++C)
10267fa27ce4SDimitry Andric     dbgs() << llvm::left_justify("| " + std::to_string(C), ColWidth);
10277fa27ce4SDimitry Andric   dbgs() << "|\n";
10287fa27ce4SDimitry Andric 
10297fa27ce4SDimitry Andric   for (MachineInstr &MI : *this) {
10307fa27ce4SDimitry Andric     SUnit *SU = getSUnit(&MI);
10317fa27ce4SDimitry Andric     if (!SU) {
10327fa27ce4SDimitry Andric       dbgs() << "Missing SUnit\n";
10337fa27ce4SDimitry Andric       continue;
10347fa27ce4SDimitry Andric     }
10357fa27ce4SDimitry Andric     std::string NodeName("SU(");
10367fa27ce4SDimitry Andric     NodeName += std::to_string(SU->NodeNum) + ")";
10377fa27ce4SDimitry Andric     dbgs() << llvm::left_justify(NodeName, HeaderColWidth);
10387fa27ce4SDimitry Andric     unsigned C = FirstCycle;
10397fa27ce4SDimitry Andric     for (; C <= LastCycle; ++C) {
10407fa27ce4SDimitry Andric       if (C == SU->TopReadyCycle)
10417fa27ce4SDimitry Andric         dbgs() << llvm::left_justify("| i", ColWidth);
10427fa27ce4SDimitry Andric       else
10437fa27ce4SDimitry Andric         dbgs() << llvm::left_justify("|", ColWidth);
10447fa27ce4SDimitry Andric     }
10457fa27ce4SDimitry Andric     dbgs() << "|\n";
10467fa27ce4SDimitry Andric     const MCSchedClassDesc *SC = getSchedClass(SU);
10477fa27ce4SDimitry Andric 
10487fa27ce4SDimitry Andric     SmallVector<MCWriteProcResEntry, 4> ResourcesIt(
10497fa27ce4SDimitry Andric         make_range(SchedModel.getWriteProcResBegin(SC),
10507fa27ce4SDimitry Andric                    SchedModel.getWriteProcResEnd(SC)));
10517fa27ce4SDimitry Andric 
10527fa27ce4SDimitry Andric     if (MISchedSortResourcesInTrace)
10537fa27ce4SDimitry Andric       llvm::stable_sort(ResourcesIt,
10547fa27ce4SDimitry Andric                         [](const MCWriteProcResEntry &LHS,
10557fa27ce4SDimitry Andric                            const MCWriteProcResEntry &RHS) -> bool {
1056b1c73532SDimitry Andric                           return LHS.AcquireAtCycle < RHS.AcquireAtCycle ||
1057b1c73532SDimitry Andric                                  (LHS.AcquireAtCycle == RHS.AcquireAtCycle &&
1058b1c73532SDimitry Andric                                   LHS.ReleaseAtCycle < RHS.ReleaseAtCycle);
10597fa27ce4SDimitry Andric                         });
10607fa27ce4SDimitry Andric     for (const MCWriteProcResEntry &PI : ResourcesIt) {
10617fa27ce4SDimitry Andric       C = FirstCycle;
10627fa27ce4SDimitry Andric       const std::string ResName =
10637fa27ce4SDimitry Andric           SchedModel.getResourceName(PI.ProcResourceIdx);
10647fa27ce4SDimitry Andric       dbgs() << llvm::right_justify(ResName + " ", HeaderColWidth);
1065b1c73532SDimitry Andric       for (; C < SU->TopReadyCycle + PI.AcquireAtCycle; ++C) {
10667fa27ce4SDimitry Andric         dbgs() << llvm::left_justify("|", ColWidth);
10677fa27ce4SDimitry Andric       }
1068b1c73532SDimitry Andric       for (unsigned I = 0, E = PI.ReleaseAtCycle - PI.AcquireAtCycle; I != E;
1069b1c73532SDimitry Andric            ++I, ++C)
10707fa27ce4SDimitry Andric         dbgs() << llvm::left_justify("| x", ColWidth);
10717fa27ce4SDimitry Andric       while (C++ <= LastCycle)
10727fa27ce4SDimitry Andric         dbgs() << llvm::left_justify("|", ColWidth);
10737fa27ce4SDimitry Andric       // Place end char
10747fa27ce4SDimitry Andric       dbgs() << "| \n";
10757fa27ce4SDimitry Andric     }
10767fa27ce4SDimitry Andric   }
10777fa27ce4SDimitry Andric }
10787fa27ce4SDimitry Andric 
dumpScheduleTraceBottomUp() const10797fa27ce4SDimitry Andric LLVM_DUMP_METHOD void ScheduleDAGMI::dumpScheduleTraceBottomUp() const {
10807fa27ce4SDimitry Andric   // Bail off when there is no schedule model to query.
10817fa27ce4SDimitry Andric   if (!SchedModel.hasInstrSchedModel())
10827fa27ce4SDimitry Andric     return;
10837fa27ce4SDimitry Andric 
10847fa27ce4SDimitry Andric   //  Nothing to show if there is no or just one instruction.
10857fa27ce4SDimitry Andric   if (BB->size() < 2)
10867fa27ce4SDimitry Andric     return;
10877fa27ce4SDimitry Andric 
10887fa27ce4SDimitry Andric   dbgs() << " * Schedule table (BottomUp):\n";
10897fa27ce4SDimitry Andric   dbgs() << scheduleTableLegend << "\n";
10907fa27ce4SDimitry Andric 
10917fa27ce4SDimitry Andric   const int FirstCycle = getSUnit(&*(std::begin(*this)))->BotReadyCycle;
10927fa27ce4SDimitry Andric   int LastCycle = getSUnit(&*(std::prev(std::end(*this))))->BotReadyCycle;
10937fa27ce4SDimitry Andric   for (MachineInstr &MI : *this) {
10947fa27ce4SDimitry Andric     SUnit *SU = getSUnit(&MI);
10957fa27ce4SDimitry Andric     if (!SU)
10967fa27ce4SDimitry Andric       continue;
10977fa27ce4SDimitry Andric     const MCSchedClassDesc *SC = getSchedClass(SU);
10987fa27ce4SDimitry Andric     for (TargetSchedModel::ProcResIter PI = SchedModel.getWriteProcResBegin(SC),
10997fa27ce4SDimitry Andric                                        PE = SchedModel.getWriteProcResEnd(SC);
11007fa27ce4SDimitry Andric          PI != PE; ++PI) {
1101b1c73532SDimitry Andric       if ((int)SU->BotReadyCycle - PI->ReleaseAtCycle + 1 < LastCycle)
1102b1c73532SDimitry Andric         LastCycle = (int)SU->BotReadyCycle - PI->ReleaseAtCycle + 1;
11037fa27ce4SDimitry Andric     }
11047fa27ce4SDimitry Andric   }
11057fa27ce4SDimitry Andric   // Print the header with the cycles
11067fa27ce4SDimitry Andric   dbgs() << llvm::left_justify("Cycle", HeaderColWidth);
11077fa27ce4SDimitry Andric   for (int C = FirstCycle; C >= LastCycle; --C)
11087fa27ce4SDimitry Andric     dbgs() << llvm::left_justify("| " + std::to_string(C), ColWidth);
11097fa27ce4SDimitry Andric   dbgs() << "|\n";
11107fa27ce4SDimitry Andric 
11117fa27ce4SDimitry Andric   for (MachineInstr &MI : *this) {
11127fa27ce4SDimitry Andric     SUnit *SU = getSUnit(&MI);
11137fa27ce4SDimitry Andric     if (!SU) {
11147fa27ce4SDimitry Andric       dbgs() << "Missing SUnit\n";
11157fa27ce4SDimitry Andric       continue;
11167fa27ce4SDimitry Andric     }
11177fa27ce4SDimitry Andric     std::string NodeName("SU(");
11187fa27ce4SDimitry Andric     NodeName += std::to_string(SU->NodeNum) + ")";
11197fa27ce4SDimitry Andric     dbgs() << llvm::left_justify(NodeName, HeaderColWidth);
11207fa27ce4SDimitry Andric     int C = FirstCycle;
11217fa27ce4SDimitry Andric     for (; C >= LastCycle; --C) {
11227fa27ce4SDimitry Andric       if (C == (int)SU->BotReadyCycle)
11237fa27ce4SDimitry Andric         dbgs() << llvm::left_justify("| i", ColWidth);
11247fa27ce4SDimitry Andric       else
11257fa27ce4SDimitry Andric         dbgs() << llvm::left_justify("|", ColWidth);
11267fa27ce4SDimitry Andric     }
11277fa27ce4SDimitry Andric     dbgs() << "|\n";
11287fa27ce4SDimitry Andric     const MCSchedClassDesc *SC = getSchedClass(SU);
11297fa27ce4SDimitry Andric     SmallVector<MCWriteProcResEntry, 4> ResourcesIt(
11307fa27ce4SDimitry Andric         make_range(SchedModel.getWriteProcResBegin(SC),
11317fa27ce4SDimitry Andric                    SchedModel.getWriteProcResEnd(SC)));
11327fa27ce4SDimitry Andric 
11337fa27ce4SDimitry Andric     if (MISchedSortResourcesInTrace)
11347fa27ce4SDimitry Andric       llvm::stable_sort(ResourcesIt,
11357fa27ce4SDimitry Andric                         [](const MCWriteProcResEntry &LHS,
11367fa27ce4SDimitry Andric                            const MCWriteProcResEntry &RHS) -> bool {
1137b1c73532SDimitry Andric                           return LHS.AcquireAtCycle < RHS.AcquireAtCycle ||
1138b1c73532SDimitry Andric                                  (LHS.AcquireAtCycle == RHS.AcquireAtCycle &&
1139b1c73532SDimitry Andric                                   LHS.ReleaseAtCycle < RHS.ReleaseAtCycle);
11407fa27ce4SDimitry Andric                         });
11417fa27ce4SDimitry Andric     for (const MCWriteProcResEntry &PI : ResourcesIt) {
11427fa27ce4SDimitry Andric       C = FirstCycle;
11437fa27ce4SDimitry Andric       const std::string ResName =
11447fa27ce4SDimitry Andric           SchedModel.getResourceName(PI.ProcResourceIdx);
11457fa27ce4SDimitry Andric       dbgs() << llvm::right_justify(ResName + " ", HeaderColWidth);
1146b1c73532SDimitry Andric       for (; C > ((int)SU->BotReadyCycle - (int)PI.AcquireAtCycle); --C) {
11477fa27ce4SDimitry Andric         dbgs() << llvm::left_justify("|", ColWidth);
11487fa27ce4SDimitry Andric       }
1149b1c73532SDimitry Andric       for (unsigned I = 0, E = PI.ReleaseAtCycle - PI.AcquireAtCycle; I != E;
1150b1c73532SDimitry Andric            ++I, --C)
11517fa27ce4SDimitry Andric         dbgs() << llvm::left_justify("| x", ColWidth);
11527fa27ce4SDimitry Andric       while (C-- >= LastCycle)
11537fa27ce4SDimitry Andric         dbgs() << llvm::left_justify("|", ColWidth);
11547fa27ce4SDimitry Andric       // Place end char
11557fa27ce4SDimitry Andric       dbgs() << "| \n";
11567fa27ce4SDimitry Andric     }
11577fa27ce4SDimitry Andric   }
11587fa27ce4SDimitry Andric }
11597fa27ce4SDimitry Andric #endif
11607fa27ce4SDimitry Andric 
11617fa27ce4SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
dumpSchedule() const116271d5a254SDimitry Andric LLVM_DUMP_METHOD void ScheduleDAGMI::dumpSchedule() const {
11637fa27ce4SDimitry Andric   if (MISchedDumpScheduleTrace) {
1164ac9a064cSDimitry Andric     if (DumpDir == DumpDirection::TopDown)
11657fa27ce4SDimitry Andric       dumpScheduleTraceTopDown();
1166ac9a064cSDimitry Andric     else if (DumpDir == DumpDirection::BottomUp)
11677fa27ce4SDimitry Andric       dumpScheduleTraceBottomUp();
1168ac9a064cSDimitry Andric     else if (DumpDir == DumpDirection::Bidirectional) {
11697fa27ce4SDimitry Andric       dbgs() << "* Schedule table (Bidirectional): not implemented\n";
1170ac9a064cSDimitry Andric     } else {
1171ac9a064cSDimitry Andric       dbgs() << "* Schedule table: DumpDirection not set.\n";
11727fa27ce4SDimitry Andric     }
11737fa27ce4SDimitry Andric   }
11747fa27ce4SDimitry Andric 
1175344a3780SDimitry Andric   for (MachineInstr &MI : *this) {
1176344a3780SDimitry Andric     if (SUnit *SU = getSUnit(&MI))
1177d8e91e46SDimitry Andric       dumpNode(*SU);
11785ca98fd9SDimitry Andric     else
11795ca98fd9SDimitry Andric       dbgs() << "Missing SUnit\n";
11805ca98fd9SDimitry Andric   }
11815ca98fd9SDimitry Andric }
11825ca98fd9SDimitry Andric #endif
11835ca98fd9SDimitry Andric 
11845ca98fd9SDimitry Andric //===----------------------------------------------------------------------===//
11855ca98fd9SDimitry Andric // ScheduleDAGMILive - Base class for MachineInstr scheduling with LiveIntervals
11865ca98fd9SDimitry Andric // preservation.
11875ca98fd9SDimitry Andric //===----------------------------------------------------------------------===//
11885ca98fd9SDimitry Andric 
~ScheduleDAGMILive()11895ca98fd9SDimitry Andric ScheduleDAGMILive::~ScheduleDAGMILive() {
11905ca98fd9SDimitry Andric   delete DFSResult;
11915ca98fd9SDimitry Andric }
11925ca98fd9SDimitry Andric 
collectVRegUses(SUnit & SU)1193b915e9e0SDimitry Andric void ScheduleDAGMILive::collectVRegUses(SUnit &SU) {
1194b915e9e0SDimitry Andric   const MachineInstr &MI = *SU.getInstr();
1195b915e9e0SDimitry Andric   for (const MachineOperand &MO : MI.operands()) {
1196b915e9e0SDimitry Andric     if (!MO.isReg())
1197b915e9e0SDimitry Andric       continue;
1198b915e9e0SDimitry Andric     if (!MO.readsReg())
1199b915e9e0SDimitry Andric       continue;
1200b915e9e0SDimitry Andric     if (TrackLaneMasks && !MO.isUse())
1201b915e9e0SDimitry Andric       continue;
1202b915e9e0SDimitry Andric 
12031d5ae102SDimitry Andric     Register Reg = MO.getReg();
1204e3b55780SDimitry Andric     if (!Reg.isVirtual())
1205b915e9e0SDimitry Andric       continue;
1206b915e9e0SDimitry Andric 
1207b915e9e0SDimitry Andric     // Ignore re-defs.
1208b915e9e0SDimitry Andric     if (TrackLaneMasks) {
1209b915e9e0SDimitry Andric       bool FoundDef = false;
12107fa27ce4SDimitry Andric       for (const MachineOperand &MO2 : MI.all_defs()) {
12117fa27ce4SDimitry Andric         if (MO2.getReg() == Reg && !MO2.isDead()) {
1212b915e9e0SDimitry Andric           FoundDef = true;
1213b915e9e0SDimitry Andric           break;
1214b915e9e0SDimitry Andric         }
1215b915e9e0SDimitry Andric       }
1216b915e9e0SDimitry Andric       if (FoundDef)
1217b915e9e0SDimitry Andric         continue;
1218b915e9e0SDimitry Andric     }
1219b915e9e0SDimitry Andric 
1220b915e9e0SDimitry Andric     // Record this local VReg use.
1221b915e9e0SDimitry Andric     VReg2SUnitMultiMap::iterator UI = VRegUses.find(Reg);
1222b915e9e0SDimitry Andric     for (; UI != VRegUses.end(); ++UI) {
1223b915e9e0SDimitry Andric       if (UI->SU == &SU)
1224b915e9e0SDimitry Andric         break;
1225b915e9e0SDimitry Andric     }
1226b915e9e0SDimitry Andric     if (UI == VRegUses.end())
1227b915e9e0SDimitry Andric       VRegUses.insert(VReg2SUnit(Reg, LaneBitmask::getNone(), &SU));
1228b915e9e0SDimitry Andric   }
1229b915e9e0SDimitry Andric }
1230b915e9e0SDimitry Andric 
123158b69754SDimitry Andric /// enterRegion - Called back from MachineScheduler::runOnMachineFunction after
123258b69754SDimitry Andric /// crossing a scheduling boundary. [begin, end) includes all instructions in
123358b69754SDimitry Andric /// the region, including the boundary itself and single-instruction regions
123458b69754SDimitry Andric /// that don't get scheduled.
enterRegion(MachineBasicBlock * bb,MachineBasicBlock::iterator begin,MachineBasicBlock::iterator end,unsigned regioninstrs)12355ca98fd9SDimitry Andric void ScheduleDAGMILive::enterRegion(MachineBasicBlock *bb,
123658b69754SDimitry Andric                                 MachineBasicBlock::iterator begin,
123758b69754SDimitry Andric                                 MachineBasicBlock::iterator end,
1238f8af5cf6SDimitry Andric                                 unsigned regioninstrs)
123958b69754SDimitry Andric {
12405ca98fd9SDimitry Andric   // ScheduleDAGMI initializes SchedImpl's per-region policy.
12415ca98fd9SDimitry Andric   ScheduleDAGMI::enterRegion(bb, begin, end, regioninstrs);
124263faed5bSDimitry Andric 
124358b69754SDimitry Andric   // For convenience remember the end of the liveness region.
12445ca98fd9SDimitry Andric   LiveRegionEnd = (RegionEnd == bb->end()) ? RegionEnd : std::next(RegionEnd);
1245f8af5cf6SDimitry Andric 
1246f8af5cf6SDimitry Andric   SUPressureDiffs.clear();
1247f8af5cf6SDimitry Andric 
1248f8af5cf6SDimitry Andric   ShouldTrackPressure = SchedImpl->shouldTrackPressure();
124901095a5dSDimitry Andric   ShouldTrackLaneMasks = SchedImpl->shouldTrackLaneMasks();
125001095a5dSDimitry Andric 
125101095a5dSDimitry Andric   assert((!ShouldTrackLaneMasks || ShouldTrackPressure) &&
125201095a5dSDimitry Andric          "ShouldTrackLaneMasks requires ShouldTrackPressure");
125358b69754SDimitry Andric }
125458b69754SDimitry Andric 
12551d5ae102SDimitry Andric // Setup the register pressure trackers for the top scheduled and bottom
125658b69754SDimitry Andric // scheduled regions.
initRegPressure()12575ca98fd9SDimitry Andric void ScheduleDAGMILive::initRegPressure() {
1258b915e9e0SDimitry Andric   VRegUses.clear();
1259b915e9e0SDimitry Andric   VRegUses.setUniverse(MRI.getNumVirtRegs());
1260b915e9e0SDimitry Andric   for (SUnit &SU : SUnits)
1261b915e9e0SDimitry Andric     collectVRegUses(SU);
1262b915e9e0SDimitry Andric 
126301095a5dSDimitry Andric   TopRPTracker.init(&MF, RegClassInfo, LIS, BB, RegionBegin,
126401095a5dSDimitry Andric                     ShouldTrackLaneMasks, false);
126501095a5dSDimitry Andric   BotRPTracker.init(&MF, RegClassInfo, LIS, BB, LiveRegionEnd,
126601095a5dSDimitry Andric                     ShouldTrackLaneMasks, false);
126758b69754SDimitry Andric 
126858b69754SDimitry Andric   // Close the RPTracker to finalize live ins.
126958b69754SDimitry Andric   RPTracker.closeRegion();
127058b69754SDimitry Andric 
1271eb11fae6SDimitry Andric   LLVM_DEBUG(RPTracker.dump());
127258b69754SDimitry Andric 
127358b69754SDimitry Andric   // Initialize the live ins and live outs.
127458b69754SDimitry Andric   TopRPTracker.addLiveRegs(RPTracker.getPressure().LiveInRegs);
127558b69754SDimitry Andric   BotRPTracker.addLiveRegs(RPTracker.getPressure().LiveOutRegs);
127658b69754SDimitry Andric 
127758b69754SDimitry Andric   // Close one end of the tracker so we can call
127858b69754SDimitry Andric   // getMaxUpward/DownwardPressureDelta before advancing across any
127958b69754SDimitry Andric   // instructions. This converts currently live regs into live ins/outs.
128058b69754SDimitry Andric   TopRPTracker.closeTop();
128158b69754SDimitry Andric   BotRPTracker.closeBottom();
128258b69754SDimitry Andric 
1283f8af5cf6SDimitry Andric   BotRPTracker.initLiveThru(RPTracker);
1284f8af5cf6SDimitry Andric   if (!BotRPTracker.getLiveThru().empty()) {
1285f8af5cf6SDimitry Andric     TopRPTracker.initLiveThru(BotRPTracker.getLiveThru());
1286eb11fae6SDimitry Andric     LLVM_DEBUG(dbgs() << "Live Thru: ";
1287f8af5cf6SDimitry Andric                dumpRegSetPressure(BotRPTracker.getLiveThru(), TRI));
1288f8af5cf6SDimitry Andric   };
1289f8af5cf6SDimitry Andric 
1290f8af5cf6SDimitry Andric   // For each live out vreg reduce the pressure change associated with other
1291f8af5cf6SDimitry Andric   // uses of the same vreg below the live-out reaching def.
1292f8af5cf6SDimitry Andric   updatePressureDiffs(RPTracker.getPressure().LiveOutRegs);
1293f8af5cf6SDimitry Andric 
129458b69754SDimitry Andric   // Account for liveness generated by the region boundary.
1295f8af5cf6SDimitry Andric   if (LiveRegionEnd != RegionEnd) {
129601095a5dSDimitry Andric     SmallVector<RegisterMaskPair, 8> LiveUses;
1297f8af5cf6SDimitry Andric     BotRPTracker.recede(&LiveUses);
1298f8af5cf6SDimitry Andric     updatePressureDiffs(LiveUses);
1299f8af5cf6SDimitry Andric   }
130058b69754SDimitry Andric 
1301eb11fae6SDimitry Andric   LLVM_DEBUG(dbgs() << "Top Pressure:\n";
1302dd58ef01SDimitry Andric              dumpRegSetPressure(TopRPTracker.getRegSetPressureAtPos(), TRI);
1303dd58ef01SDimitry Andric              dbgs() << "Bottom Pressure:\n";
1304eb11fae6SDimitry Andric              dumpRegSetPressure(BotRPTracker.getRegSetPressureAtPos(), TRI););
1305dd58ef01SDimitry Andric 
1306044eb2f6SDimitry Andric   assert((BotRPTracker.getPos() == RegionEnd ||
1307eb11fae6SDimitry Andric           (RegionEnd->isDebugInstr() &&
1308044eb2f6SDimitry Andric            BotRPTracker.getPos() == priorNonDebug(RegionEnd, RegionBegin))) &&
1309044eb2f6SDimitry Andric          "Can't find the region bottom");
131058b69754SDimitry Andric 
131158b69754SDimitry Andric   // Cache the list of excess pressure sets in this region. This will also track
131258b69754SDimitry Andric   // the max pressure in the scheduled code for these sets.
131358b69754SDimitry Andric   RegionCriticalPSets.clear();
13144a16efa3SDimitry Andric   const std::vector<unsigned> &RegionPressure =
13154a16efa3SDimitry Andric     RPTracker.getPressure().MaxSetPressure;
131658b69754SDimitry Andric   for (unsigned i = 0, e = RegionPressure.size(); i < e; ++i) {
1317f8af5cf6SDimitry Andric     unsigned Limit = RegClassInfo->getRegPressureSetLimit(i);
1318f8af5cf6SDimitry Andric     if (RegionPressure[i] > Limit) {
1319eb11fae6SDimitry Andric       LLVM_DEBUG(dbgs() << TRI->getRegPressureSetName(i) << " Limit " << Limit
1320522600a2SDimitry Andric                         << " Actual " << RegionPressure[i] << "\n");
1321f8af5cf6SDimitry Andric       RegionCriticalPSets.push_back(PressureChange(i));
1322f8af5cf6SDimitry Andric     }
132358b69754SDimitry Andric   }
1324eb11fae6SDimitry Andric   LLVM_DEBUG(dbgs() << "Excess PSets: ";
1325eb11fae6SDimitry Andric              for (const PressureChange &RCPS
1326eb11fae6SDimitry Andric                   : RegionCriticalPSets) dbgs()
1327eb11fae6SDimitry Andric              << TRI->getRegPressureSetName(RCPS.getPSet()) << " ";
132858b69754SDimitry Andric              dbgs() << "\n");
132958b69754SDimitry Andric }
133058b69754SDimitry Andric 
13315ca98fd9SDimitry Andric void ScheduleDAGMILive::
updateScheduledPressure(const SUnit * SU,const std::vector<unsigned> & NewMaxPressure)1332f8af5cf6SDimitry Andric updateScheduledPressure(const SUnit *SU,
1333f8af5cf6SDimitry Andric                         const std::vector<unsigned> &NewMaxPressure) {
1334f8af5cf6SDimitry Andric   const PressureDiff &PDiff = getPressureDiff(SU);
1335f8af5cf6SDimitry Andric   unsigned CritIdx = 0, CritEnd = RegionCriticalPSets.size();
133608bbd35aSDimitry Andric   for (const PressureChange &PC : PDiff) {
133708bbd35aSDimitry Andric     if (!PC.isValid())
1338f8af5cf6SDimitry Andric       break;
133908bbd35aSDimitry Andric     unsigned ID = PC.getPSet();
1340f8af5cf6SDimitry Andric     while (CritIdx != CritEnd && RegionCriticalPSets[CritIdx].getPSet() < ID)
1341f8af5cf6SDimitry Andric       ++CritIdx;
1342f8af5cf6SDimitry Andric     if (CritIdx != CritEnd && RegionCriticalPSets[CritIdx].getPSet() == ID) {
1343f8af5cf6SDimitry Andric       if ((int)NewMaxPressure[ID] > RegionCriticalPSets[CritIdx].getUnitInc()
134471d5a254SDimitry Andric           && NewMaxPressure[ID] <= (unsigned)std::numeric_limits<int16_t>::max())
1345f8af5cf6SDimitry Andric         RegionCriticalPSets[CritIdx].setUnitInc(NewMaxPressure[ID]);
134658b69754SDimitry Andric     }
1347f8af5cf6SDimitry Andric     unsigned Limit = RegClassInfo->getRegPressureSetLimit(ID);
1348f8af5cf6SDimitry Andric     if (NewMaxPressure[ID] >= Limit - 2) {
1349eb11fae6SDimitry Andric       LLVM_DEBUG(dbgs() << "  " << TRI->getRegPressureSetName(ID) << ": "
13505a5ac124SDimitry Andric                         << NewMaxPressure[ID]
1351eb11fae6SDimitry Andric                         << ((NewMaxPressure[ID] > Limit) ? " > " : " <= ")
1352eb11fae6SDimitry Andric                         << Limit << "(+ " << BotRPTracker.getLiveThru()[ID]
1353eb11fae6SDimitry Andric                         << " livethru)\n");
135459d6cff9SDimitry Andric     }
1355f8af5cf6SDimitry Andric   }
1356f8af5cf6SDimitry Andric }
1357f8af5cf6SDimitry Andric 
1358f8af5cf6SDimitry Andric /// Update the PressureDiff array for liveness after scheduling this
1359f8af5cf6SDimitry Andric /// instruction.
updatePressureDiffs(ArrayRef<RegisterMaskPair> LiveUses)136001095a5dSDimitry Andric void ScheduleDAGMILive::updatePressureDiffs(
136101095a5dSDimitry Andric     ArrayRef<RegisterMaskPair> LiveUses) {
136201095a5dSDimitry Andric   for (const RegisterMaskPair &P : LiveUses) {
1363b60736ecSDimitry Andric     Register Reg = P.RegUnit;
1364f8af5cf6SDimitry Andric     /// FIXME: Currently assuming single-use physregs.
1365e3b55780SDimitry Andric     if (!Reg.isVirtual())
1366f8af5cf6SDimitry Andric       continue;
1367f8af5cf6SDimitry Andric 
136801095a5dSDimitry Andric     if (ShouldTrackLaneMasks) {
136901095a5dSDimitry Andric       // If the register has just become live then other uses won't change
137001095a5dSDimitry Andric       // this fact anymore => decrement pressure.
137101095a5dSDimitry Andric       // If the register has just become dead then other uses make it come
137201095a5dSDimitry Andric       // back to life => increment pressure.
1373b915e9e0SDimitry Andric       bool Decrement = P.LaneMask.any();
137401095a5dSDimitry Andric 
137501095a5dSDimitry Andric       for (const VReg2SUnit &V2SU
137601095a5dSDimitry Andric            : make_range(VRegUses.find(Reg), VRegUses.end())) {
137701095a5dSDimitry Andric         SUnit &SU = *V2SU.SU;
137801095a5dSDimitry Andric         if (SU.isScheduled || &SU == &ExitSU)
137901095a5dSDimitry Andric           continue;
138001095a5dSDimitry Andric 
138101095a5dSDimitry Andric         PressureDiff &PDiff = getPressureDiff(&SU);
138201095a5dSDimitry Andric         PDiff.addPressureChange(Reg, Decrement, &MRI);
1383eb11fae6SDimitry Andric         LLVM_DEBUG(dbgs() << "  UpdateRegP: SU(" << SU.NodeNum << ") "
1384eb11fae6SDimitry Andric                           << printReg(Reg, TRI) << ':'
1385eb11fae6SDimitry Andric                           << PrintLaneMask(P.LaneMask) << ' ' << *SU.getInstr();
1386eb11fae6SDimitry Andric                    dbgs() << "              to "; PDiff.dump(*TRI););
138701095a5dSDimitry Andric       }
138801095a5dSDimitry Andric     } else {
1389b915e9e0SDimitry Andric       assert(P.LaneMask.any());
1390eb11fae6SDimitry Andric       LLVM_DEBUG(dbgs() << "  LiveReg: " << printVRegOrUnit(Reg, TRI) << "\n");
1391f8af5cf6SDimitry Andric       // This may be called before CurrentBottom has been initialized. However,
1392f8af5cf6SDimitry Andric       // BotRPTracker must have a valid position. We want the value live into the
1393f8af5cf6SDimitry Andric       // instruction or live out of the block, so ask for the previous
1394f8af5cf6SDimitry Andric       // instruction's live-out.
1395f8af5cf6SDimitry Andric       const LiveInterval &LI = LIS->getInterval(Reg);
1396f8af5cf6SDimitry Andric       VNInfo *VNI;
1397f8af5cf6SDimitry Andric       MachineBasicBlock::const_iterator I =
1398f8af5cf6SDimitry Andric         nextIfDebug(BotRPTracker.getPos(), BB->end());
1399f8af5cf6SDimitry Andric       if (I == BB->end())
1400f8af5cf6SDimitry Andric         VNI = LI.getVNInfoBefore(LIS->getMBBEndIdx(BB));
1401f8af5cf6SDimitry Andric       else {
140201095a5dSDimitry Andric         LiveQueryResult LRQ = LI.Query(LIS->getInstructionIndex(*I));
1403f8af5cf6SDimitry Andric         VNI = LRQ.valueIn();
1404f8af5cf6SDimitry Andric       }
1405f8af5cf6SDimitry Andric       // RegisterPressureTracker guarantees that readsReg is true for LiveUses.
1406f8af5cf6SDimitry Andric       assert(VNI && "No live value at use.");
1407dd58ef01SDimitry Andric       for (const VReg2SUnit &V2SU
1408dd58ef01SDimitry Andric            : make_range(VRegUses.find(Reg), VRegUses.end())) {
1409dd58ef01SDimitry Andric         SUnit *SU = V2SU.SU;
141001095a5dSDimitry Andric         // If this use comes before the reaching def, it cannot be a last use,
141101095a5dSDimitry Andric         // so decrease its pressure change.
1412f8af5cf6SDimitry Andric         if (!SU->isScheduled && SU != &ExitSU) {
141301095a5dSDimitry Andric           LiveQueryResult LRQ =
141401095a5dSDimitry Andric               LI.Query(LIS->getInstructionIndex(*SU->getInstr()));
1415dd58ef01SDimitry Andric           if (LRQ.valueIn() == VNI) {
1416dd58ef01SDimitry Andric             PressureDiff &PDiff = getPressureDiff(SU);
1417dd58ef01SDimitry Andric             PDiff.addPressureChange(Reg, true, &MRI);
1418eb11fae6SDimitry Andric             LLVM_DEBUG(dbgs() << "  UpdateRegP: SU(" << SU->NodeNum << ") "
1419dd58ef01SDimitry Andric                               << *SU->getInstr();
1420eb11fae6SDimitry Andric                        dbgs() << "              to "; PDiff.dump(*TRI););
1421dd58ef01SDimitry Andric           }
1422f8af5cf6SDimitry Andric         }
1423f8af5cf6SDimitry Andric       }
1424f8af5cf6SDimitry Andric     }
142558b69754SDimitry Andric   }
142601095a5dSDimitry Andric }
142758b69754SDimitry Andric 
dump() const1428d8e91e46SDimitry Andric void ScheduleDAGMILive::dump() const {
1429d8e91e46SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
1430d8e91e46SDimitry Andric   if (EntrySU.getInstr() != nullptr)
1431d8e91e46SDimitry Andric     dumpNodeAll(EntrySU);
1432d8e91e46SDimitry Andric   for (const SUnit &SU : SUnits) {
1433d8e91e46SDimitry Andric     dumpNodeAll(SU);
1434d8e91e46SDimitry Andric     if (ShouldTrackPressure) {
1435d8e91e46SDimitry Andric       dbgs() << "  Pressure Diff      : ";
1436d8e91e46SDimitry Andric       getPressureDiff(&SU).dump(*TRI);
1437d8e91e46SDimitry Andric     }
1438d8e91e46SDimitry Andric     dbgs() << "  Single Issue       : ";
1439d8e91e46SDimitry Andric     if (SchedModel.mustBeginGroup(SU.getInstr()) &&
1440d8e91e46SDimitry Andric         SchedModel.mustEndGroup(SU.getInstr()))
1441d8e91e46SDimitry Andric       dbgs() << "true;";
1442d8e91e46SDimitry Andric     else
1443d8e91e46SDimitry Andric       dbgs() << "false;";
1444d8e91e46SDimitry Andric     dbgs() << '\n';
1445d8e91e46SDimitry Andric   }
1446d8e91e46SDimitry Andric   if (ExitSU.getInstr() != nullptr)
1447d8e91e46SDimitry Andric     dumpNodeAll(ExitSU);
1448d8e91e46SDimitry Andric #endif
1449d8e91e46SDimitry Andric }
1450d8e91e46SDimitry Andric 
1451522600a2SDimitry Andric /// schedule - Called back from MachineScheduler::runOnMachineFunction
1452522600a2SDimitry Andric /// after setting up the current scheduling region. [RegionBegin, RegionEnd)
1453522600a2SDimitry Andric /// only includes instructions that have DAG nodes, not scheduling boundaries.
1454522600a2SDimitry Andric ///
1455522600a2SDimitry Andric /// This is a skeletal driver, with all the functionality pushed into helpers,
1456dd58ef01SDimitry Andric /// so that it can be easily extended by experimental schedulers. Generally,
1457522600a2SDimitry Andric /// implementing MachineSchedStrategy should be sufficient to implement a new
1458522600a2SDimitry Andric /// scheduling algorithm. However, if a scheduler further subclasses
14595ca98fd9SDimitry Andric /// ScheduleDAGMILive then it will want to override this virtual method in order
14605ca98fd9SDimitry Andric /// to update any specialized state.
schedule()14615ca98fd9SDimitry Andric void ScheduleDAGMILive::schedule() {
1462eb11fae6SDimitry Andric   LLVM_DEBUG(dbgs() << "ScheduleDAGMILive::schedule starting\n");
1463eb11fae6SDimitry Andric   LLVM_DEBUG(SchedImpl->dumpPolicy());
1464522600a2SDimitry Andric   buildDAGWithRegPressure();
1465522600a2SDimitry Andric 
14667fa27ce4SDimitry Andric   postProcessDAG();
1467522600a2SDimitry Andric 
14684a16efa3SDimitry Andric   SmallVector<SUnit*, 8> TopRoots, BotRoots;
14694a16efa3SDimitry Andric   findRootsAndBiasEdges(TopRoots, BotRoots);
14704a16efa3SDimitry Andric 
14714a16efa3SDimitry Andric   // Initialize the strategy before modifying the DAG.
14724a16efa3SDimitry Andric   // This may initialize a DFSResult to be used for queue priority.
14734a16efa3SDimitry Andric   SchedImpl->initialize(this);
14744a16efa3SDimitry Andric 
1475d8e91e46SDimitry Andric   LLVM_DEBUG(dump());
1476d8e91e46SDimitry Andric   if (PrintDAGs) dump();
1477522600a2SDimitry Andric   if (ViewMISchedDAGs) viewGraph();
1478522600a2SDimitry Andric 
14794a16efa3SDimitry Andric   // Initialize ready queues now that the DAG and priority data are finalized.
14804a16efa3SDimitry Andric   initQueues(TopRoots, BotRoots);
1481522600a2SDimitry Andric 
1482522600a2SDimitry Andric   bool IsTopNode = false;
1483dd58ef01SDimitry Andric   while (true) {
1484eb11fae6SDimitry Andric     LLVM_DEBUG(dbgs() << "** ScheduleDAGMILive::schedule picking next node\n");
1485dd58ef01SDimitry Andric     SUnit *SU = SchedImpl->pickNode(IsTopNode);
1486dd58ef01SDimitry Andric     if (!SU) break;
1487dd58ef01SDimitry Andric 
1488522600a2SDimitry Andric     assert(!SU->isScheduled && "Node already scheduled");
1489522600a2SDimitry Andric     if (!checkSchedLimit())
1490522600a2SDimitry Andric       break;
1491522600a2SDimitry Andric 
1492522600a2SDimitry Andric     scheduleMI(SU, IsTopNode);
1493522600a2SDimitry Andric 
14945ca98fd9SDimitry Andric     if (DFSResult) {
14955ca98fd9SDimitry Andric       unsigned SubtreeID = DFSResult->getSubtreeID(SU);
14965ca98fd9SDimitry Andric       if (!ScheduledTrees.test(SubtreeID)) {
14975ca98fd9SDimitry Andric         ScheduledTrees.set(SubtreeID);
14985ca98fd9SDimitry Andric         DFSResult->scheduleTree(SubtreeID);
14995ca98fd9SDimitry Andric         SchedImpl->scheduleTree(SubtreeID);
15005ca98fd9SDimitry Andric       }
15015ca98fd9SDimitry Andric     }
15025ca98fd9SDimitry Andric 
15035ca98fd9SDimitry Andric     // Notify the scheduling strategy after updating the DAG.
15045ca98fd9SDimitry Andric     SchedImpl->schedNode(SU, IsTopNode);
15055a5ac124SDimitry Andric 
15065a5ac124SDimitry Andric     updateQueues(SU, IsTopNode);
1507522600a2SDimitry Andric   }
1508522600a2SDimitry Andric   assert(CurrentTop == CurrentBottom && "Nonempty unscheduled zone.");
1509522600a2SDimitry Andric 
1510522600a2SDimitry Andric   placeDebugValues();
1511522600a2SDimitry Andric 
1512eb11fae6SDimitry Andric   LLVM_DEBUG({
1513044eb2f6SDimitry Andric     dbgs() << "*** Final schedule for "
1514044eb2f6SDimitry Andric            << printMBBReference(*begin()->getParent()) << " ***\n";
1515522600a2SDimitry Andric     dumpSchedule();
1516522600a2SDimitry Andric     dbgs() << '\n';
1517522600a2SDimitry Andric   });
1518522600a2SDimitry Andric }
1519522600a2SDimitry Andric 
1520522600a2SDimitry Andric /// Build the DAG and setup three register pressure trackers.
buildDAGWithRegPressure()15215ca98fd9SDimitry Andric void ScheduleDAGMILive::buildDAGWithRegPressure() {
1522f8af5cf6SDimitry Andric   if (!ShouldTrackPressure) {
1523f8af5cf6SDimitry Andric     RPTracker.reset();
1524f8af5cf6SDimitry Andric     RegionCriticalPSets.clear();
1525f8af5cf6SDimitry Andric     buildSchedGraph(AA);
1526f8af5cf6SDimitry Andric     return;
1527f8af5cf6SDimitry Andric   }
1528f8af5cf6SDimitry Andric 
1529522600a2SDimitry Andric   // Initialize the register pressure tracker used by buildSchedGraph.
1530f8af5cf6SDimitry Andric   RPTracker.init(&MF, RegClassInfo, LIS, BB, LiveRegionEnd,
153101095a5dSDimitry Andric                  ShouldTrackLaneMasks, /*TrackUntiedDefs=*/true);
1532522600a2SDimitry Andric 
1533522600a2SDimitry Andric   // Account for liveness generate by the region boundary.
1534522600a2SDimitry Andric   if (LiveRegionEnd != RegionEnd)
1535522600a2SDimitry Andric     RPTracker.recede();
1536522600a2SDimitry Andric 
1537522600a2SDimitry Andric   // Build the DAG, and compute current register pressure.
153801095a5dSDimitry Andric   buildSchedGraph(AA, &RPTracker, &SUPressureDiffs, LIS, ShouldTrackLaneMasks);
1539522600a2SDimitry Andric 
1540522600a2SDimitry Andric   // Initialize top/bottom trackers after computing region pressure.
1541522600a2SDimitry Andric   initRegPressure();
1542522600a2SDimitry Andric }
1543522600a2SDimitry Andric 
computeDFSResult()15445ca98fd9SDimitry Andric void ScheduleDAGMILive::computeDFSResult() {
15454a16efa3SDimitry Andric   if (!DFSResult)
15464a16efa3SDimitry Andric     DFSResult = new SchedDFSResult(/*BottomU*/true, MinSubtreeSize);
15474a16efa3SDimitry Andric   DFSResult->clear();
15484a16efa3SDimitry Andric   ScheduledTrees.clear();
15494a16efa3SDimitry Andric   DFSResult->resize(SUnits.size());
15504a16efa3SDimitry Andric   DFSResult->compute(SUnits);
15514a16efa3SDimitry Andric   ScheduledTrees.resize(DFSResult->getNumSubtrees());
15524a16efa3SDimitry Andric }
155358b69754SDimitry Andric 
1554f8af5cf6SDimitry Andric /// Compute the max cyclic critical path through the DAG. The scheduling DAG
1555f8af5cf6SDimitry Andric /// only provides the critical path for single block loops. To handle loops that
1556f8af5cf6SDimitry Andric /// span blocks, we could use the vreg path latencies provided by
1557f8af5cf6SDimitry Andric /// MachineTraceMetrics instead. However, MachineTraceMetrics is not currently
1558f8af5cf6SDimitry Andric /// available for use in the scheduler.
1559f8af5cf6SDimitry Andric ///
1560f8af5cf6SDimitry Andric /// The cyclic path estimation identifies a def-use pair that crosses the back
1561f8af5cf6SDimitry Andric /// edge and considers the depth and height of the nodes. For example, consider
1562f8af5cf6SDimitry Andric /// the following instruction sequence where each instruction has unit latency
1563b60736ecSDimitry Andric /// and defines an eponymous virtual register:
1564f8af5cf6SDimitry Andric ///
1565f8af5cf6SDimitry Andric /// a->b(a,c)->c(b)->d(c)->exit
1566f8af5cf6SDimitry Andric ///
1567f8af5cf6SDimitry Andric /// The cyclic critical path is a two cycles: b->c->b
1568f8af5cf6SDimitry Andric /// The acyclic critical path is four cycles: a->b->c->d->exit
1569f8af5cf6SDimitry Andric /// LiveOutHeight = height(c) = len(c->d->exit) = 2
1570f8af5cf6SDimitry Andric /// LiveOutDepth = depth(c) + 1 = len(a->b->c) + 1 = 3
1571f8af5cf6SDimitry Andric /// LiveInHeight = height(b) + 1 = len(b->c->d->exit) + 1 = 4
1572f8af5cf6SDimitry Andric /// LiveInDepth = depth(b) = len(a->b) = 1
1573f8af5cf6SDimitry Andric ///
1574f8af5cf6SDimitry Andric /// LiveOutDepth - LiveInDepth = 3 - 1 = 2
1575f8af5cf6SDimitry Andric /// LiveInHeight - LiveOutHeight = 4 - 2 = 2
1576f8af5cf6SDimitry Andric /// CyclicCriticalPath = min(2, 2) = 2
15775ca98fd9SDimitry Andric ///
15785ca98fd9SDimitry Andric /// This could be relevant to PostRA scheduling, but is currently implemented
15795ca98fd9SDimitry Andric /// assuming LiveIntervals.
computeCyclicCriticalPath()15805ca98fd9SDimitry Andric unsigned ScheduleDAGMILive::computeCyclicCriticalPath() {
1581f8af5cf6SDimitry Andric   // This only applies to single block loop.
1582f8af5cf6SDimitry Andric   if (!BB->isSuccessor(BB))
1583f8af5cf6SDimitry Andric     return 0;
1584f8af5cf6SDimitry Andric 
1585f8af5cf6SDimitry Andric   unsigned MaxCyclicLatency = 0;
1586f8af5cf6SDimitry Andric   // Visit each live out vreg def to find def/use pairs that cross iterations.
158701095a5dSDimitry Andric   for (const RegisterMaskPair &P : RPTracker.getPressure().LiveOutRegs) {
1588b60736ecSDimitry Andric     Register Reg = P.RegUnit;
1589e3b55780SDimitry Andric     if (!Reg.isVirtual())
1590f8af5cf6SDimitry Andric       continue;
1591f8af5cf6SDimitry Andric     const LiveInterval &LI = LIS->getInterval(Reg);
1592f8af5cf6SDimitry Andric     const VNInfo *DefVNI = LI.getVNInfoBefore(LIS->getMBBEndIdx(BB));
1593f8af5cf6SDimitry Andric     if (!DefVNI)
1594f8af5cf6SDimitry Andric       continue;
1595f8af5cf6SDimitry Andric 
1596f8af5cf6SDimitry Andric     MachineInstr *DefMI = LIS->getInstructionFromIndex(DefVNI->def);
1597f8af5cf6SDimitry Andric     const SUnit *DefSU = getSUnit(DefMI);
1598f8af5cf6SDimitry Andric     if (!DefSU)
1599f8af5cf6SDimitry Andric       continue;
1600f8af5cf6SDimitry Andric 
1601f8af5cf6SDimitry Andric     unsigned LiveOutHeight = DefSU->getHeight();
1602f8af5cf6SDimitry Andric     unsigned LiveOutDepth = DefSU->getDepth() + DefSU->Latency;
1603f8af5cf6SDimitry Andric     // Visit all local users of the vreg def.
1604dd58ef01SDimitry Andric     for (const VReg2SUnit &V2SU
1605dd58ef01SDimitry Andric          : make_range(VRegUses.find(Reg), VRegUses.end())) {
1606dd58ef01SDimitry Andric       SUnit *SU = V2SU.SU;
1607dd58ef01SDimitry Andric       if (SU == &ExitSU)
1608f8af5cf6SDimitry Andric         continue;
1609f8af5cf6SDimitry Andric 
1610f8af5cf6SDimitry Andric       // Only consider uses of the phi.
161101095a5dSDimitry Andric       LiveQueryResult LRQ = LI.Query(LIS->getInstructionIndex(*SU->getInstr()));
1612f8af5cf6SDimitry Andric       if (!LRQ.valueIn()->isPHIDef())
1613f8af5cf6SDimitry Andric         continue;
1614f8af5cf6SDimitry Andric 
1615f8af5cf6SDimitry Andric       // Assume that a path spanning two iterations is a cycle, which could
1616f8af5cf6SDimitry Andric       // overestimate in strange cases. This allows cyclic latency to be
1617f8af5cf6SDimitry Andric       // estimated as the minimum slack of the vreg's depth or height.
1618f8af5cf6SDimitry Andric       unsigned CyclicLatency = 0;
1619dd58ef01SDimitry Andric       if (LiveOutDepth > SU->getDepth())
1620dd58ef01SDimitry Andric         CyclicLatency = LiveOutDepth - SU->getDepth();
1621f8af5cf6SDimitry Andric 
1622dd58ef01SDimitry Andric       unsigned LiveInHeight = SU->getHeight() + DefSU->Latency;
1623f8af5cf6SDimitry Andric       if (LiveInHeight > LiveOutHeight) {
1624f8af5cf6SDimitry Andric         if (LiveInHeight - LiveOutHeight < CyclicLatency)
1625f8af5cf6SDimitry Andric           CyclicLatency = LiveInHeight - LiveOutHeight;
162601095a5dSDimitry Andric       } else
1627f8af5cf6SDimitry Andric         CyclicLatency = 0;
1628f8af5cf6SDimitry Andric 
1629eb11fae6SDimitry Andric       LLVM_DEBUG(dbgs() << "Cyclic Path: SU(" << DefSU->NodeNum << ") -> SU("
1630dd58ef01SDimitry Andric                         << SU->NodeNum << ") = " << CyclicLatency << "c\n");
1631f8af5cf6SDimitry Andric       if (CyclicLatency > MaxCyclicLatency)
1632f8af5cf6SDimitry Andric         MaxCyclicLatency = CyclicLatency;
1633f8af5cf6SDimitry Andric     }
1634f8af5cf6SDimitry Andric   }
1635eb11fae6SDimitry Andric   LLVM_DEBUG(dbgs() << "Cyclic Critical Path: " << MaxCyclicLatency << "c\n");
1636f8af5cf6SDimitry Andric   return MaxCyclicLatency;
1637f8af5cf6SDimitry Andric }
1638f8af5cf6SDimitry Andric 
163901095a5dSDimitry Andric /// Release ExitSU predecessors and setup scheduler queues. Re-position
164001095a5dSDimitry Andric /// the Top RP tracker in case the region beginning has changed.
initQueues(ArrayRef<SUnit * > TopRoots,ArrayRef<SUnit * > BotRoots)164101095a5dSDimitry Andric void ScheduleDAGMILive::initQueues(ArrayRef<SUnit*> TopRoots,
164201095a5dSDimitry Andric                                    ArrayRef<SUnit*> BotRoots) {
164301095a5dSDimitry Andric   ScheduleDAGMI::initQueues(TopRoots, BotRoots);
164401095a5dSDimitry Andric   if (ShouldTrackPressure) {
164501095a5dSDimitry Andric     assert(TopRPTracker.getPos() == RegionBegin && "bad initial Top tracker");
164601095a5dSDimitry Andric     TopRPTracker.setPos(CurrentTop);
164701095a5dSDimitry Andric   }
164801095a5dSDimitry Andric }
164901095a5dSDimitry Andric 
1650522600a2SDimitry Andric /// Move an instruction and update register pressure.
scheduleMI(SUnit * SU,bool IsTopNode)16515ca98fd9SDimitry Andric void ScheduleDAGMILive::scheduleMI(SUnit *SU, bool IsTopNode) {
165263faed5bSDimitry Andric   // Move the instruction to its new location in the instruction stream.
165363faed5bSDimitry Andric   MachineInstr *MI = SU->getInstr();
165463faed5bSDimitry Andric 
165563faed5bSDimitry Andric   if (IsTopNode) {
165663faed5bSDimitry Andric     assert(SU->isTopReady() && "node still has unscheduled dependencies");
165763faed5bSDimitry Andric     if (&*CurrentTop == MI)
165858b69754SDimitry Andric       CurrentTop = nextIfDebug(++CurrentTop, CurrentBottom);
165958b69754SDimitry Andric     else {
166063faed5bSDimitry Andric       moveInstruction(MI, CurrentTop);
166158b69754SDimitry Andric       TopRPTracker.setPos(MI);
166258b69754SDimitry Andric     }
166358b69754SDimitry Andric 
1664f8af5cf6SDimitry Andric     if (ShouldTrackPressure) {
166558b69754SDimitry Andric       // Update top scheduled pressure.
166601095a5dSDimitry Andric       RegisterOperands RegOpers;
1667ac9a064cSDimitry Andric       RegOpers.collect(*MI, *TRI, MRI, ShouldTrackLaneMasks,
1668ac9a064cSDimitry Andric                        /*IgnoreDead=*/false);
166901095a5dSDimitry Andric       if (ShouldTrackLaneMasks) {
167001095a5dSDimitry Andric         // Adjust liveness and add missing dead+read-undef flags.
167101095a5dSDimitry Andric         SlotIndex SlotIdx = LIS->getInstructionIndex(*MI).getRegSlot();
167201095a5dSDimitry Andric         RegOpers.adjustLaneLiveness(*LIS, MRI, SlotIdx, MI);
167301095a5dSDimitry Andric       } else {
167401095a5dSDimitry Andric         // Adjust for missing dead-def flags.
167501095a5dSDimitry Andric         RegOpers.detectDeadDefs(*MI, *LIS);
167601095a5dSDimitry Andric       }
167701095a5dSDimitry Andric 
167801095a5dSDimitry Andric       TopRPTracker.advance(RegOpers);
167958b69754SDimitry Andric       assert(TopRPTracker.getPos() == CurrentTop && "out of sync");
1680eb11fae6SDimitry Andric       LLVM_DEBUG(dbgs() << "Top Pressure:\n"; dumpRegSetPressure(
1681eb11fae6SDimitry Andric                      TopRPTracker.getRegSetPressureAtPos(), TRI););
1682dd58ef01SDimitry Andric 
1683f8af5cf6SDimitry Andric       updateScheduledPressure(SU, TopRPTracker.getPressure().MaxSetPressure);
1684f8af5cf6SDimitry Andric     }
168501095a5dSDimitry Andric   } else {
168663faed5bSDimitry Andric     assert(SU->isBottomReady() && "node still has unscheduled dependencies");
168758b69754SDimitry Andric     MachineBasicBlock::iterator priorII =
168858b69754SDimitry Andric       priorNonDebug(CurrentBottom, CurrentTop);
168958b69754SDimitry Andric     if (&*priorII == MI)
169058b69754SDimitry Andric       CurrentBottom = priorII;
169163faed5bSDimitry Andric     else {
169258b69754SDimitry Andric       if (&*CurrentTop == MI) {
169358b69754SDimitry Andric         CurrentTop = nextIfDebug(++CurrentTop, priorII);
169458b69754SDimitry Andric         TopRPTracker.setPos(CurrentTop);
169558b69754SDimitry Andric       }
169663faed5bSDimitry Andric       moveInstruction(MI, CurrentBottom);
169763faed5bSDimitry Andric       CurrentBottom = MI;
1698eb11fae6SDimitry Andric       BotRPTracker.setPos(CurrentBottom);
169963faed5bSDimitry Andric     }
1700f8af5cf6SDimitry Andric     if (ShouldTrackPressure) {
170101095a5dSDimitry Andric       RegisterOperands RegOpers;
1702ac9a064cSDimitry Andric       RegOpers.collect(*MI, *TRI, MRI, ShouldTrackLaneMasks,
1703ac9a064cSDimitry Andric                        /*IgnoreDead=*/false);
170401095a5dSDimitry Andric       if (ShouldTrackLaneMasks) {
170501095a5dSDimitry Andric         // Adjust liveness and add missing dead+read-undef flags.
170601095a5dSDimitry Andric         SlotIndex SlotIdx = LIS->getInstructionIndex(*MI).getRegSlot();
170701095a5dSDimitry Andric         RegOpers.adjustLaneLiveness(*LIS, MRI, SlotIdx, MI);
170801095a5dSDimitry Andric       } else {
170901095a5dSDimitry Andric         // Adjust for missing dead-def flags.
171001095a5dSDimitry Andric         RegOpers.detectDeadDefs(*MI, *LIS);
171101095a5dSDimitry Andric       }
171201095a5dSDimitry Andric 
1713044eb2f6SDimitry Andric       if (BotRPTracker.getPos() != CurrentBottom)
171401095a5dSDimitry Andric         BotRPTracker.recedeSkipDebugValues();
171501095a5dSDimitry Andric       SmallVector<RegisterMaskPair, 8> LiveUses;
171601095a5dSDimitry Andric       BotRPTracker.recede(RegOpers, &LiveUses);
171758b69754SDimitry Andric       assert(BotRPTracker.getPos() == CurrentBottom && "out of sync");
1718eb11fae6SDimitry Andric       LLVM_DEBUG(dbgs() << "Bottom Pressure:\n"; dumpRegSetPressure(
1719eb11fae6SDimitry Andric                      BotRPTracker.getRegSetPressureAtPos(), TRI););
1720dd58ef01SDimitry Andric 
1721f8af5cf6SDimitry Andric       updateScheduledPressure(SU, BotRPTracker.getPressure().MaxSetPressure);
1722f8af5cf6SDimitry Andric       updatePressureDiffs(LiveUses);
1723f8af5cf6SDimitry Andric     }
1724522600a2SDimitry Andric   }
1725522600a2SDimitry Andric }
172658b69754SDimitry Andric 
172763faed5bSDimitry Andric //===----------------------------------------------------------------------===//
172801095a5dSDimitry Andric // BaseMemOpClusterMutation - DAG post-processing to cluster loads or stores.
17294a16efa3SDimitry Andric //===----------------------------------------------------------------------===//
17304a16efa3SDimitry Andric 
17314a16efa3SDimitry Andric namespace {
173271d5a254SDimitry Andric 
1733eb11fae6SDimitry Andric /// Post-process the DAG to create cluster edges between neighboring
173401095a5dSDimitry Andric /// loads or between neighboring stores.
173501095a5dSDimitry Andric class BaseMemOpClusterMutation : public ScheduleDAGMutation {
173601095a5dSDimitry Andric   struct MemOpInfo {
17374a16efa3SDimitry Andric     SUnit *SU;
1738cfca06d7SDimitry Andric     SmallVector<const MachineOperand *, 4> BaseOps;
173901095a5dSDimitry Andric     int64_t Offset;
1740ac9a064cSDimitry Andric     LocationSize Width;
1741b1c73532SDimitry Andric     bool OffsetIsScalable;
174271d5a254SDimitry Andric 
MemOpInfo__anon233174dd0511::BaseMemOpClusterMutation::MemOpInfo1743cfca06d7SDimitry Andric     MemOpInfo(SUnit *SU, ArrayRef<const MachineOperand *> BaseOps,
1744ac9a064cSDimitry Andric               int64_t Offset, bool OffsetIsScalable, LocationSize Width)
1745cfca06d7SDimitry Andric         : SU(SU), BaseOps(BaseOps.begin(), BaseOps.end()), Offset(Offset),
1746b1c73532SDimitry Andric           Width(Width), OffsetIsScalable(OffsetIsScalable) {}
17475ca98fd9SDimitry Andric 
Compare__anon233174dd0511::BaseMemOpClusterMutation::MemOpInfo1748cfca06d7SDimitry Andric     static bool Compare(const MachineOperand *const &A,
1749cfca06d7SDimitry Andric                         const MachineOperand *const &B) {
1750cfca06d7SDimitry Andric       if (A->getType() != B->getType())
1751cfca06d7SDimitry Andric         return A->getType() < B->getType();
1752cfca06d7SDimitry Andric       if (A->isReg())
1753cfca06d7SDimitry Andric         return A->getReg() < B->getReg();
1754cfca06d7SDimitry Andric       if (A->isFI()) {
1755cfca06d7SDimitry Andric         const MachineFunction &MF = *A->getParent()->getParent()->getParent();
1756d8e91e46SDimitry Andric         const TargetFrameLowering &TFI = *MF.getSubtarget().getFrameLowering();
1757d8e91e46SDimitry Andric         bool StackGrowsDown = TFI.getStackGrowthDirection() ==
1758d8e91e46SDimitry Andric                               TargetFrameLowering::StackGrowsDown;
1759cfca06d7SDimitry Andric         return StackGrowsDown ? A->getIndex() > B->getIndex()
1760cfca06d7SDimitry Andric                               : A->getIndex() < B->getIndex();
1761d8e91e46SDimitry Andric       }
1762d8e91e46SDimitry Andric 
1763d8e91e46SDimitry Andric       llvm_unreachable("MemOpClusterMutation only supports register or frame "
1764d8e91e46SDimitry Andric                        "index bases.");
17655ca98fd9SDimitry Andric     }
1766cfca06d7SDimitry Andric 
operator <__anon233174dd0511::BaseMemOpClusterMutation::MemOpInfo1767cfca06d7SDimitry Andric     bool operator<(const MemOpInfo &RHS) const {
1768cfca06d7SDimitry Andric       // FIXME: Don't compare everything twice. Maybe use C++20 three way
1769cfca06d7SDimitry Andric       // comparison instead when it's available.
1770cfca06d7SDimitry Andric       if (std::lexicographical_compare(BaseOps.begin(), BaseOps.end(),
1771cfca06d7SDimitry Andric                                        RHS.BaseOps.begin(), RHS.BaseOps.end(),
1772cfca06d7SDimitry Andric                                        Compare))
1773cfca06d7SDimitry Andric         return true;
1774cfca06d7SDimitry Andric       if (std::lexicographical_compare(RHS.BaseOps.begin(), RHS.BaseOps.end(),
1775cfca06d7SDimitry Andric                                        BaseOps.begin(), BaseOps.end(), Compare))
1776cfca06d7SDimitry Andric         return false;
1777cfca06d7SDimitry Andric       if (Offset != RHS.Offset)
1778cfca06d7SDimitry Andric         return Offset < RHS.Offset;
1779cfca06d7SDimitry Andric       return SU->NodeNum < RHS.SU->NodeNum;
1780cfca06d7SDimitry Andric     }
17814a16efa3SDimitry Andric   };
17824a16efa3SDimitry Andric 
17834a16efa3SDimitry Andric   const TargetInstrInfo *TII;
17844a16efa3SDimitry Andric   const TargetRegisterInfo *TRI;
178501095a5dSDimitry Andric   bool IsLoad;
17864df029ccSDimitry Andric   bool ReorderWhileClustering;
17874a16efa3SDimitry Andric 
178801095a5dSDimitry Andric public:
BaseMemOpClusterMutation(const TargetInstrInfo * tii,const TargetRegisterInfo * tri,bool IsLoad,bool ReorderWhileClustering)178901095a5dSDimitry Andric   BaseMemOpClusterMutation(const TargetInstrInfo *tii,
17904df029ccSDimitry Andric                            const TargetRegisterInfo *tri, bool IsLoad,
17914df029ccSDimitry Andric                            bool ReorderWhileClustering)
17924df029ccSDimitry Andric       : TII(tii), TRI(tri), IsLoad(IsLoad),
17934df029ccSDimitry Andric         ReorderWhileClustering(ReorderWhileClustering) {}
179401095a5dSDimitry Andric 
179501095a5dSDimitry Andric   void apply(ScheduleDAGInstrs *DAGInstrs) override;
179601095a5dSDimitry Andric 
17974a16efa3SDimitry Andric protected:
1798b60736ecSDimitry Andric   void clusterNeighboringMemOps(ArrayRef<MemOpInfo> MemOps, bool FastCluster,
1799b60736ecSDimitry Andric                                 ScheduleDAGInstrs *DAG);
1800b60736ecSDimitry Andric   void collectMemOpRecords(std::vector<SUnit> &SUnits,
1801b60736ecSDimitry Andric                            SmallVectorImpl<MemOpInfo> &MemOpRecords);
1802b60736ecSDimitry Andric   bool groupMemOps(ArrayRef<MemOpInfo> MemOps, ScheduleDAGInstrs *DAG,
1803b60736ecSDimitry Andric                    DenseMap<unsigned, SmallVector<MemOpInfo, 32>> &Groups);
180401095a5dSDimitry Andric };
180501095a5dSDimitry Andric 
180601095a5dSDimitry Andric class StoreClusterMutation : public BaseMemOpClusterMutation {
180701095a5dSDimitry Andric public:
StoreClusterMutation(const TargetInstrInfo * tii,const TargetRegisterInfo * tri,bool ReorderWhileClustering)180801095a5dSDimitry Andric   StoreClusterMutation(const TargetInstrInfo *tii,
18094df029ccSDimitry Andric                        const TargetRegisterInfo *tri,
18104df029ccSDimitry Andric                        bool ReorderWhileClustering)
18114df029ccSDimitry Andric       : BaseMemOpClusterMutation(tii, tri, false, ReorderWhileClustering) {}
181201095a5dSDimitry Andric };
181301095a5dSDimitry Andric 
181401095a5dSDimitry Andric class LoadClusterMutation : public BaseMemOpClusterMutation {
181501095a5dSDimitry Andric public:
LoadClusterMutation(const TargetInstrInfo * tii,const TargetRegisterInfo * tri,bool ReorderWhileClustering)18164df029ccSDimitry Andric   LoadClusterMutation(const TargetInstrInfo *tii, const TargetRegisterInfo *tri,
18174df029ccSDimitry Andric                       bool ReorderWhileClustering)
18184df029ccSDimitry Andric       : BaseMemOpClusterMutation(tii, tri, true, ReorderWhileClustering) {}
18194a16efa3SDimitry Andric };
182071d5a254SDimitry Andric 
182171d5a254SDimitry Andric } // end anonymous namespace
18224a16efa3SDimitry Andric 
1823b915e9e0SDimitry Andric namespace llvm {
1824b915e9e0SDimitry Andric 
1825b915e9e0SDimitry Andric std::unique_ptr<ScheduleDAGMutation>
createLoadClusterDAGMutation(const TargetInstrInfo * TII,const TargetRegisterInfo * TRI,bool ReorderWhileClustering)1826b915e9e0SDimitry Andric createLoadClusterDAGMutation(const TargetInstrInfo *TII,
18274df029ccSDimitry Andric                              const TargetRegisterInfo *TRI,
18284df029ccSDimitry Andric                              bool ReorderWhileClustering) {
18294df029ccSDimitry Andric   return EnableMemOpCluster ? std::make_unique<LoadClusterMutation>(
18304df029ccSDimitry Andric                                   TII, TRI, ReorderWhileClustering)
1831b915e9e0SDimitry Andric                             : nullptr;
1832b915e9e0SDimitry Andric }
1833b915e9e0SDimitry Andric 
1834b915e9e0SDimitry Andric std::unique_ptr<ScheduleDAGMutation>
createStoreClusterDAGMutation(const TargetInstrInfo * TII,const TargetRegisterInfo * TRI,bool ReorderWhileClustering)1835b915e9e0SDimitry Andric createStoreClusterDAGMutation(const TargetInstrInfo *TII,
18364df029ccSDimitry Andric                               const TargetRegisterInfo *TRI,
18374df029ccSDimitry Andric                               bool ReorderWhileClustering) {
18384df029ccSDimitry Andric   return EnableMemOpCluster ? std::make_unique<StoreClusterMutation>(
18394df029ccSDimitry Andric                                   TII, TRI, ReorderWhileClustering)
1840b915e9e0SDimitry Andric                             : nullptr;
1841b915e9e0SDimitry Andric }
1842b915e9e0SDimitry Andric 
184371d5a254SDimitry Andric } // end namespace llvm
1844b915e9e0SDimitry Andric 
1845b60736ecSDimitry Andric // Sorting all the loads/stores first, then for each load/store, checking the
1846b60736ecSDimitry Andric // following load/store one by one, until reach the first non-dependent one and
1847b60736ecSDimitry Andric // call target hook to see if they can cluster.
1848b60736ecSDimitry Andric // If FastCluster is enabled, we assume that, all the loads/stores have been
1849b60736ecSDimitry Andric // preprocessed and now, they didn't have dependencies on each other.
clusterNeighboringMemOps(ArrayRef<MemOpInfo> MemOpRecords,bool FastCluster,ScheduleDAGInstrs * DAG)185001095a5dSDimitry Andric void BaseMemOpClusterMutation::clusterNeighboringMemOps(
1851b60736ecSDimitry Andric     ArrayRef<MemOpInfo> MemOpRecords, bool FastCluster,
1852b60736ecSDimitry Andric     ScheduleDAGInstrs *DAG) {
1853b60736ecSDimitry Andric   // Keep track of the current cluster length and bytes for each SUnit.
1854b60736ecSDimitry Andric   DenseMap<unsigned, std::pair<unsigned, unsigned>> SUnit2ClusterInfo;
1855cfca06d7SDimitry Andric 
1856cfca06d7SDimitry Andric   // At this point, `MemOpRecords` array must hold atleast two mem ops. Try to
1857cfca06d7SDimitry Andric   // cluster mem ops collected within `MemOpRecords` array.
185801095a5dSDimitry Andric   for (unsigned Idx = 0, End = MemOpRecords.size(); Idx < (End - 1); ++Idx) {
1859cfca06d7SDimitry Andric     // Decision to cluster mem ops is taken based on target dependent logic
1860cfca06d7SDimitry Andric     auto MemOpa = MemOpRecords[Idx];
1861b60736ecSDimitry Andric 
1862b60736ecSDimitry Andric     // Seek for the next load/store to do the cluster.
1863b60736ecSDimitry Andric     unsigned NextIdx = Idx + 1;
1864b60736ecSDimitry Andric     for (; NextIdx < End; ++NextIdx)
1865b60736ecSDimitry Andric       // Skip if MemOpb has been clustered already or has dependency with
1866b60736ecSDimitry Andric       // MemOpa.
1867b60736ecSDimitry Andric       if (!SUnit2ClusterInfo.count(MemOpRecords[NextIdx].SU->NodeNum) &&
1868b60736ecSDimitry Andric           (FastCluster ||
1869b60736ecSDimitry Andric            (!DAG->IsReachable(MemOpRecords[NextIdx].SU, MemOpa.SU) &&
1870b60736ecSDimitry Andric             !DAG->IsReachable(MemOpa.SU, MemOpRecords[NextIdx].SU))))
1871b60736ecSDimitry Andric         break;
1872b60736ecSDimitry Andric     if (NextIdx == End)
1873cfca06d7SDimitry Andric       continue;
1874b60736ecSDimitry Andric 
1875b60736ecSDimitry Andric     auto MemOpb = MemOpRecords[NextIdx];
1876b60736ecSDimitry Andric     unsigned ClusterLength = 2;
1877ac9a064cSDimitry Andric     unsigned CurrentClusterBytes = MemOpa.Width.getValue().getKnownMinValue() +
1878ac9a064cSDimitry Andric                                    MemOpb.Width.getValue().getKnownMinValue();
1879b60736ecSDimitry Andric     if (SUnit2ClusterInfo.count(MemOpa.SU->NodeNum)) {
1880b60736ecSDimitry Andric       ClusterLength = SUnit2ClusterInfo[MemOpa.SU->NodeNum].first + 1;
1881ac9a064cSDimitry Andric       CurrentClusterBytes = SUnit2ClusterInfo[MemOpa.SU->NodeNum].second +
1882ac9a064cSDimitry Andric                             MemOpb.Width.getValue().getKnownMinValue();
1883cfca06d7SDimitry Andric     }
1884cfca06d7SDimitry Andric 
1885b1c73532SDimitry Andric     if (!TII->shouldClusterMemOps(MemOpa.BaseOps, MemOpa.Offset,
1886b1c73532SDimitry Andric                                   MemOpa.OffsetIsScalable, MemOpb.BaseOps,
1887b1c73532SDimitry Andric                                   MemOpb.Offset, MemOpb.OffsetIsScalable,
1888b1c73532SDimitry Andric                                   ClusterLength, CurrentClusterBytes))
1889b60736ecSDimitry Andric       continue;
1890b60736ecSDimitry Andric 
1891cfca06d7SDimitry Andric     SUnit *SUa = MemOpa.SU;
1892cfca06d7SDimitry Andric     SUnit *SUb = MemOpb.SU;
18934df029ccSDimitry Andric     if (!ReorderWhileClustering && SUa->NodeNum > SUb->NodeNum)
1894706b4fc4SDimitry Andric       std::swap(SUa, SUb);
1895cfca06d7SDimitry Andric 
1896cfca06d7SDimitry Andric     // FIXME: Is this check really required?
1897b60736ecSDimitry Andric     if (!DAG->addEdge(SUb, SDep(SUa, SDep::Cluster)))
1898cfca06d7SDimitry Andric       continue;
1899cfca06d7SDimitry Andric 
1900eb11fae6SDimitry Andric     LLVM_DEBUG(dbgs() << "Cluster ld/st SU(" << SUa->NodeNum << ") - SU("
19014a16efa3SDimitry Andric                       << SUb->NodeNum << ")\n");
1902b60736ecSDimitry Andric     ++NumClustered;
1903cfca06d7SDimitry Andric 
1904b60736ecSDimitry Andric     if (IsLoad) {
19054a16efa3SDimitry Andric       // Copy successor edges from SUa to SUb. Interleaving computation
19064a16efa3SDimitry Andric       // dependent on SUa can prevent load combining due to register reuse.
1907cfca06d7SDimitry Andric       // Predecessor edges do not need to be copied from SUb to SUa since
1908cfca06d7SDimitry Andric       // nearby loads should have effectively the same inputs.
190908bbd35aSDimitry Andric       for (const SDep &Succ : SUa->Succs) {
191008bbd35aSDimitry Andric         if (Succ.getSUnit() == SUb)
19114a16efa3SDimitry Andric           continue;
1912eb11fae6SDimitry Andric         LLVM_DEBUG(dbgs() << "  Copy Succ SU(" << Succ.getSUnit()->NodeNum
1913eb11fae6SDimitry Andric                           << ")\n");
191408bbd35aSDimitry Andric         DAG->addEdge(Succ.getSUnit(), SDep(SUb, SDep::Artificial));
19154a16efa3SDimitry Andric       }
1916b60736ecSDimitry Andric     } else {
1917b60736ecSDimitry Andric       // Copy predecessor edges from SUb to SUa to avoid the SUnits that
1918b60736ecSDimitry Andric       // SUb dependent on scheduled in-between SUb and SUa. Successor edges
1919b60736ecSDimitry Andric       // do not need to be copied from SUa to SUb since no one will depend
1920b60736ecSDimitry Andric       // on stores.
1921b60736ecSDimitry Andric       // Notice that, we don't need to care about the memory dependency as
1922b60736ecSDimitry Andric       // we won't try to cluster them if they have any memory dependency.
1923b60736ecSDimitry Andric       for (const SDep &Pred : SUb->Preds) {
1924b60736ecSDimitry Andric         if (Pred.getSUnit() == SUa)
1925b60736ecSDimitry Andric           continue;
1926b60736ecSDimitry Andric         LLVM_DEBUG(dbgs() << "  Copy Pred SU(" << Pred.getSUnit()->NodeNum
1927b60736ecSDimitry Andric                           << ")\n");
1928b60736ecSDimitry Andric         DAG->addEdge(SUa, SDep(Pred.getSUnit(), SDep::Artificial));
1929b60736ecSDimitry Andric       }
1930b60736ecSDimitry Andric     }
1931b60736ecSDimitry Andric 
1932b60736ecSDimitry Andric     SUnit2ClusterInfo[MemOpb.SU->NodeNum] = {ClusterLength,
1933b60736ecSDimitry Andric                                              CurrentClusterBytes};
1934cfca06d7SDimitry Andric 
1935cfca06d7SDimitry Andric     LLVM_DEBUG(dbgs() << "  Curr cluster length: " << ClusterLength
1936cfca06d7SDimitry Andric                       << ", Curr cluster bytes: " << CurrentClusterBytes
1937cfca06d7SDimitry Andric                       << "\n");
19384a16efa3SDimitry Andric   }
19394a16efa3SDimitry Andric }
19404a16efa3SDimitry Andric 
collectMemOpRecords(std::vector<SUnit> & SUnits,SmallVectorImpl<MemOpInfo> & MemOpRecords)1941b60736ecSDimitry Andric void BaseMemOpClusterMutation::collectMemOpRecords(
1942b60736ecSDimitry Andric     std::vector<SUnit> &SUnits, SmallVectorImpl<MemOpInfo> &MemOpRecords) {
1943b60736ecSDimitry Andric   for (auto &SU : SUnits) {
194408bbd35aSDimitry Andric     if ((IsLoad && !SU.getInstr()->mayLoad()) ||
194508bbd35aSDimitry Andric         (!IsLoad && !SU.getInstr()->mayStore()))
19464a16efa3SDimitry Andric       continue;
194701095a5dSDimitry Andric 
1948b60736ecSDimitry Andric     const MachineInstr &MI = *SU.getInstr();
1949b60736ecSDimitry Andric     SmallVector<const MachineOperand *, 4> BaseOps;
1950b60736ecSDimitry Andric     int64_t Offset;
1951b60736ecSDimitry Andric     bool OffsetIsScalable;
1952ac9a064cSDimitry Andric     LocationSize Width = 0;
1953b60736ecSDimitry Andric     if (TII->getMemOperandsWithOffsetWidth(MI, BaseOps, Offset,
1954b60736ecSDimitry Andric                                            OffsetIsScalable, Width, TRI)) {
1955b1c73532SDimitry Andric       MemOpRecords.push_back(
1956b1c73532SDimitry Andric           MemOpInfo(&SU, BaseOps, Offset, OffsetIsScalable, Width));
1957b60736ecSDimitry Andric 
1958b60736ecSDimitry Andric       LLVM_DEBUG(dbgs() << "Num BaseOps: " << BaseOps.size() << ", Offset: "
1959b60736ecSDimitry Andric                         << Offset << ", OffsetIsScalable: " << OffsetIsScalable
1960b60736ecSDimitry Andric                         << ", Width: " << Width << "\n");
1961b60736ecSDimitry Andric     }
1962b60736ecSDimitry Andric #ifndef NDEBUG
19634b4fe385SDimitry Andric     for (const auto *Op : BaseOps)
1964b60736ecSDimitry Andric       assert(Op);
1965b60736ecSDimitry Andric #endif
1966b60736ecSDimitry Andric   }
1967b60736ecSDimitry Andric }
1968b60736ecSDimitry Andric 
groupMemOps(ArrayRef<MemOpInfo> MemOps,ScheduleDAGInstrs * DAG,DenseMap<unsigned,SmallVector<MemOpInfo,32>> & Groups)1969b60736ecSDimitry Andric bool BaseMemOpClusterMutation::groupMemOps(
1970b60736ecSDimitry Andric     ArrayRef<MemOpInfo> MemOps, ScheduleDAGInstrs *DAG,
1971b60736ecSDimitry Andric     DenseMap<unsigned, SmallVector<MemOpInfo, 32>> &Groups) {
1972b60736ecSDimitry Andric   bool FastCluster =
1973b60736ecSDimitry Andric       ForceFastCluster ||
1974b60736ecSDimitry Andric       MemOps.size() * DAG->SUnits.size() / 1000 > FastClusterThreshold;
1975b60736ecSDimitry Andric 
1976b60736ecSDimitry Andric   for (const auto &MemOp : MemOps) {
19774a16efa3SDimitry Andric     unsigned ChainPredID = DAG->SUnits.size();
1978b60736ecSDimitry Andric     if (FastCluster) {
1979b60736ecSDimitry Andric       for (const SDep &Pred : MemOp.SU->Preds) {
1980b60736ecSDimitry Andric         // We only want to cluster the mem ops that have the same ctrl(non-data)
1981b60736ecSDimitry Andric         // pred so that they didn't have ctrl dependency for each other. But for
1982b60736ecSDimitry Andric         // store instrs, we can still cluster them if the pred is load instr.
1983b60736ecSDimitry Andric         if ((Pred.isCtrl() &&
1984b60736ecSDimitry Andric              (IsLoad ||
1985b60736ecSDimitry Andric               (Pred.getSUnit() && Pred.getSUnit()->getInstr()->mayStore()))) &&
1986b60736ecSDimitry Andric             !Pred.isArtificial()) {
198708bbd35aSDimitry Andric           ChainPredID = Pred.getSUnit()->NodeNum;
19884a16efa3SDimitry Andric           break;
19894a16efa3SDimitry Andric         }
19904a16efa3SDimitry Andric       }
1991b60736ecSDimitry Andric     } else
1992b60736ecSDimitry Andric       ChainPredID = 0;
1993b60736ecSDimitry Andric 
1994b60736ecSDimitry Andric     Groups[ChainPredID].push_back(MemOp);
1995b60736ecSDimitry Andric   }
1996b60736ecSDimitry Andric   return FastCluster;
19974a16efa3SDimitry Andric }
199801095a5dSDimitry Andric 
1999b60736ecSDimitry Andric /// Callback from DAG postProcessing to create cluster edges for loads/stores.
apply(ScheduleDAGInstrs * DAG)2000b60736ecSDimitry Andric void BaseMemOpClusterMutation::apply(ScheduleDAGInstrs *DAG) {
2001b60736ecSDimitry Andric   // Collect all the clusterable loads/stores
2002b60736ecSDimitry Andric   SmallVector<MemOpInfo, 32> MemOpRecords;
2003b60736ecSDimitry Andric   collectMemOpRecords(DAG->SUnits, MemOpRecords);
2004b60736ecSDimitry Andric 
2005b60736ecSDimitry Andric   if (MemOpRecords.size() < 2)
2006b60736ecSDimitry Andric     return;
2007b60736ecSDimitry Andric 
2008b60736ecSDimitry Andric   // Put the loads/stores without dependency into the same group with some
2009b60736ecSDimitry Andric   // heuristic if the DAG is too complex to avoid compiling time blow up.
2010b60736ecSDimitry Andric   // Notice that, some fusion pair could be lost with this.
2011b60736ecSDimitry Andric   DenseMap<unsigned, SmallVector<MemOpInfo, 32>> Groups;
2012b60736ecSDimitry Andric   bool FastCluster = groupMemOps(MemOpRecords, DAG, Groups);
2013b60736ecSDimitry Andric 
2014b60736ecSDimitry Andric   for (auto &Group : Groups) {
2015b60736ecSDimitry Andric     // Sorting the loads/stores, so that, we can stop the cluster as early as
2016b60736ecSDimitry Andric     // possible.
2017b60736ecSDimitry Andric     llvm::sort(Group.second);
2018b60736ecSDimitry Andric 
2019b60736ecSDimitry Andric     // Trying to cluster all the neighboring loads/stores.
2020b60736ecSDimitry Andric     clusterNeighboringMemOps(Group.second, FastCluster, DAG);
2021b60736ecSDimitry Andric   }
20224a16efa3SDimitry Andric }
20234a16efa3SDimitry Andric 
20244a16efa3SDimitry Andric //===----------------------------------------------------------------------===//
202559d6cff9SDimitry Andric // CopyConstrain - DAG post-processing to encourage copy elimination.
202659d6cff9SDimitry Andric //===----------------------------------------------------------------------===//
202759d6cff9SDimitry Andric 
202859d6cff9SDimitry Andric namespace {
202971d5a254SDimitry Andric 
2030eb11fae6SDimitry Andric /// Post-process the DAG to create weak edges from all uses of a copy to
203159d6cff9SDimitry Andric /// the one use that defines the copy's source vreg, most likely an induction
203259d6cff9SDimitry Andric /// variable increment.
203359d6cff9SDimitry Andric class CopyConstrain : public ScheduleDAGMutation {
203459d6cff9SDimitry Andric   // Transient state.
203559d6cff9SDimitry Andric   SlotIndex RegionBeginIdx;
2036044eb2f6SDimitry Andric 
203759d6cff9SDimitry Andric   // RegionEndIdx is the slot index of the last non-debug instruction in the
203859d6cff9SDimitry Andric   // scheduling region. So we may have RegionBeginIdx == RegionEndIdx.
203959d6cff9SDimitry Andric   SlotIndex RegionEndIdx;
204071d5a254SDimitry Andric 
204159d6cff9SDimitry Andric public:
CopyConstrain(const TargetInstrInfo *,const TargetRegisterInfo *)204259d6cff9SDimitry Andric   CopyConstrain(const TargetInstrInfo *, const TargetRegisterInfo *) {}
204359d6cff9SDimitry Andric 
204401095a5dSDimitry Andric   void apply(ScheduleDAGInstrs *DAGInstrs) override;
204559d6cff9SDimitry Andric 
204659d6cff9SDimitry Andric protected:
20475ca98fd9SDimitry Andric   void constrainLocalCopy(SUnit *CopySU, ScheduleDAGMILive *DAG);
204859d6cff9SDimitry Andric };
204971d5a254SDimitry Andric 
205071d5a254SDimitry Andric } // end anonymous namespace
205159d6cff9SDimitry Andric 
2052b915e9e0SDimitry Andric namespace llvm {
2053b915e9e0SDimitry Andric 
2054b915e9e0SDimitry Andric std::unique_ptr<ScheduleDAGMutation>
createCopyConstrainDAGMutation(const TargetInstrInfo * TII,const TargetRegisterInfo * TRI)2055b915e9e0SDimitry Andric createCopyConstrainDAGMutation(const TargetInstrInfo *TII,
2056b915e9e0SDimitry Andric                                const TargetRegisterInfo *TRI) {
20571d5ae102SDimitry Andric   return std::make_unique<CopyConstrain>(TII, TRI);
2058b915e9e0SDimitry Andric }
2059b915e9e0SDimitry Andric 
206071d5a254SDimitry Andric } // end namespace llvm
2061b915e9e0SDimitry Andric 
206259d6cff9SDimitry Andric /// constrainLocalCopy handles two possibilities:
206359d6cff9SDimitry Andric /// 1) Local src:
206459d6cff9SDimitry Andric /// I0:     = dst
206559d6cff9SDimitry Andric /// I1: src = ...
206659d6cff9SDimitry Andric /// I2:     = dst
206759d6cff9SDimitry Andric /// I3: dst = src (copy)
206859d6cff9SDimitry Andric /// (create pred->succ edges I0->I1, I2->I1)
206959d6cff9SDimitry Andric ///
207059d6cff9SDimitry Andric /// 2) Local copy:
207159d6cff9SDimitry Andric /// I0: dst = src (copy)
207259d6cff9SDimitry Andric /// I1:     = dst
207359d6cff9SDimitry Andric /// I2: src = ...
207459d6cff9SDimitry Andric /// I3:     = dst
207559d6cff9SDimitry Andric /// (create pred->succ edges I1->I2, I3->I2)
207659d6cff9SDimitry Andric ///
207759d6cff9SDimitry Andric /// Although the MachineScheduler is currently constrained to single blocks,
207859d6cff9SDimitry Andric /// this algorithm should handle extended blocks. An EBB is a set of
207959d6cff9SDimitry Andric /// contiguously numbered blocks such that the previous block in the EBB is
208059d6cff9SDimitry Andric /// always the single predecessor.
constrainLocalCopy(SUnit * CopySU,ScheduleDAGMILive * DAG)20815ca98fd9SDimitry Andric void CopyConstrain::constrainLocalCopy(SUnit *CopySU, ScheduleDAGMILive *DAG) {
208259d6cff9SDimitry Andric   LiveIntervals *LIS = DAG->getLIS();
208359d6cff9SDimitry Andric   MachineInstr *Copy = CopySU->getInstr();
208459d6cff9SDimitry Andric 
208559d6cff9SDimitry Andric   // Check for pure vreg copies.
208601095a5dSDimitry Andric   const MachineOperand &SrcOp = Copy->getOperand(1);
20871d5ae102SDimitry Andric   Register SrcReg = SrcOp.getReg();
2088e3b55780SDimitry Andric   if (!SrcReg.isVirtual() || !SrcOp.readsReg())
208959d6cff9SDimitry Andric     return;
209059d6cff9SDimitry Andric 
209101095a5dSDimitry Andric   const MachineOperand &DstOp = Copy->getOperand(0);
20921d5ae102SDimitry Andric   Register DstReg = DstOp.getReg();
2093e3b55780SDimitry Andric   if (!DstReg.isVirtual() || DstOp.isDead())
209459d6cff9SDimitry Andric     return;
209559d6cff9SDimitry Andric 
209659d6cff9SDimitry Andric   // Check if either the dest or source is local. If it's live across a back
209759d6cff9SDimitry Andric   // edge, it's not local. Note that if both vregs are live across the back
209859d6cff9SDimitry Andric   // edge, we cannot successfully contrain the copy without cyclic scheduling.
20995a5ac124SDimitry Andric   // If both the copy's source and dest are local live intervals, then we
21005a5ac124SDimitry Andric   // should treat the dest as the global for the purpose of adding
21015a5ac124SDimitry Andric   // constraints. This adds edges from source's other uses to the copy.
21025a5ac124SDimitry Andric   unsigned LocalReg = SrcReg;
21035a5ac124SDimitry Andric   unsigned GlobalReg = DstReg;
210459d6cff9SDimitry Andric   LiveInterval *LocalLI = &LIS->getInterval(LocalReg);
210559d6cff9SDimitry Andric   if (!LocalLI->isLocal(RegionBeginIdx, RegionEndIdx)) {
21065a5ac124SDimitry Andric     LocalReg = DstReg;
21075a5ac124SDimitry Andric     GlobalReg = SrcReg;
210859d6cff9SDimitry Andric     LocalLI = &LIS->getInterval(LocalReg);
210959d6cff9SDimitry Andric     if (!LocalLI->isLocal(RegionBeginIdx, RegionEndIdx))
211059d6cff9SDimitry Andric       return;
211159d6cff9SDimitry Andric   }
211259d6cff9SDimitry Andric   LiveInterval *GlobalLI = &LIS->getInterval(GlobalReg);
211359d6cff9SDimitry Andric 
211459d6cff9SDimitry Andric   // Find the global segment after the start of the local LI.
211559d6cff9SDimitry Andric   LiveInterval::iterator GlobalSegment = GlobalLI->find(LocalLI->beginIndex());
211659d6cff9SDimitry Andric   // If GlobalLI does not overlap LocalLI->start, then a copy directly feeds a
211759d6cff9SDimitry Andric   // local live range. We could create edges from other global uses to the local
211859d6cff9SDimitry Andric   // start, but the coalescer should have already eliminated these cases, so
211959d6cff9SDimitry Andric   // don't bother dealing with it.
212059d6cff9SDimitry Andric   if (GlobalSegment == GlobalLI->end())
212159d6cff9SDimitry Andric     return;
212259d6cff9SDimitry Andric 
212359d6cff9SDimitry Andric   // If GlobalSegment is killed at the LocalLI->start, the call to find()
212459d6cff9SDimitry Andric   // returned the next global segment. But if GlobalSegment overlaps with
2125eb11fae6SDimitry Andric   // LocalLI->start, then advance to the next segment. If a hole in GlobalLI
212659d6cff9SDimitry Andric   // exists in LocalLI's vicinity, GlobalSegment will be the end of the hole.
212759d6cff9SDimitry Andric   if (GlobalSegment->contains(LocalLI->beginIndex()))
212859d6cff9SDimitry Andric     ++GlobalSegment;
212959d6cff9SDimitry Andric 
213059d6cff9SDimitry Andric   if (GlobalSegment == GlobalLI->end())
213159d6cff9SDimitry Andric     return;
213259d6cff9SDimitry Andric 
213359d6cff9SDimitry Andric   // Check if GlobalLI contains a hole in the vicinity of LocalLI.
213459d6cff9SDimitry Andric   if (GlobalSegment != GlobalLI->begin()) {
213559d6cff9SDimitry Andric     // Two address defs have no hole.
21365ca98fd9SDimitry Andric     if (SlotIndex::isSameInstr(std::prev(GlobalSegment)->end,
213759d6cff9SDimitry Andric                                GlobalSegment->start)) {
213859d6cff9SDimitry Andric       return;
213959d6cff9SDimitry Andric     }
2140f8af5cf6SDimitry Andric     // If the prior global segment may be defined by the same two-address
2141f8af5cf6SDimitry Andric     // instruction that also defines LocalLI, then can't make a hole here.
21425ca98fd9SDimitry Andric     if (SlotIndex::isSameInstr(std::prev(GlobalSegment)->start,
2143f8af5cf6SDimitry Andric                                LocalLI->beginIndex())) {
2144f8af5cf6SDimitry Andric       return;
2145f8af5cf6SDimitry Andric     }
214659d6cff9SDimitry Andric     // If GlobalLI has a prior segment, it must be live into the EBB. Otherwise
214759d6cff9SDimitry Andric     // it would be a disconnected component in the live range.
21485ca98fd9SDimitry Andric     assert(std::prev(GlobalSegment)->start < LocalLI->beginIndex() &&
214959d6cff9SDimitry Andric            "Disconnected LRG within the scheduling region.");
215059d6cff9SDimitry Andric   }
215159d6cff9SDimitry Andric   MachineInstr *GlobalDef = LIS->getInstructionFromIndex(GlobalSegment->start);
215259d6cff9SDimitry Andric   if (!GlobalDef)
215359d6cff9SDimitry Andric     return;
215459d6cff9SDimitry Andric 
215559d6cff9SDimitry Andric   SUnit *GlobalSU = DAG->getSUnit(GlobalDef);
215659d6cff9SDimitry Andric   if (!GlobalSU)
215759d6cff9SDimitry Andric     return;
215859d6cff9SDimitry Andric 
215959d6cff9SDimitry Andric   // GlobalDef is the bottom of the GlobalLI hole. Open the hole by
216059d6cff9SDimitry Andric   // constraining the uses of the last local def to precede GlobalDef.
216159d6cff9SDimitry Andric   SmallVector<SUnit*,8> LocalUses;
216259d6cff9SDimitry Andric   const VNInfo *LastLocalVN = LocalLI->getVNInfoBefore(LocalLI->endIndex());
216359d6cff9SDimitry Andric   MachineInstr *LastLocalDef = LIS->getInstructionFromIndex(LastLocalVN->def);
216459d6cff9SDimitry Andric   SUnit *LastLocalSU = DAG->getSUnit(LastLocalDef);
216508bbd35aSDimitry Andric   for (const SDep &Succ : LastLocalSU->Succs) {
216608bbd35aSDimitry Andric     if (Succ.getKind() != SDep::Data || Succ.getReg() != LocalReg)
216759d6cff9SDimitry Andric       continue;
216808bbd35aSDimitry Andric     if (Succ.getSUnit() == GlobalSU)
216959d6cff9SDimitry Andric       continue;
217008bbd35aSDimitry Andric     if (!DAG->canAddEdge(GlobalSU, Succ.getSUnit()))
217159d6cff9SDimitry Andric       return;
217208bbd35aSDimitry Andric     LocalUses.push_back(Succ.getSUnit());
217359d6cff9SDimitry Andric   }
217459d6cff9SDimitry Andric   // Open the top of the GlobalLI hole by constraining any earlier global uses
217559d6cff9SDimitry Andric   // to precede the start of LocalLI.
217659d6cff9SDimitry Andric   SmallVector<SUnit*,8> GlobalUses;
217759d6cff9SDimitry Andric   MachineInstr *FirstLocalDef =
217859d6cff9SDimitry Andric     LIS->getInstructionFromIndex(LocalLI->beginIndex());
217959d6cff9SDimitry Andric   SUnit *FirstLocalSU = DAG->getSUnit(FirstLocalDef);
218008bbd35aSDimitry Andric   for (const SDep &Pred : GlobalSU->Preds) {
218108bbd35aSDimitry Andric     if (Pred.getKind() != SDep::Anti || Pred.getReg() != GlobalReg)
218259d6cff9SDimitry Andric       continue;
218308bbd35aSDimitry Andric     if (Pred.getSUnit() == FirstLocalSU)
218459d6cff9SDimitry Andric       continue;
218508bbd35aSDimitry Andric     if (!DAG->canAddEdge(FirstLocalSU, Pred.getSUnit()))
218659d6cff9SDimitry Andric       return;
218708bbd35aSDimitry Andric     GlobalUses.push_back(Pred.getSUnit());
218859d6cff9SDimitry Andric   }
2189eb11fae6SDimitry Andric   LLVM_DEBUG(dbgs() << "Constraining copy SU(" << CopySU->NodeNum << ")\n");
219059d6cff9SDimitry Andric   // Add the weak edges.
2191344a3780SDimitry Andric   for (SUnit *LU : LocalUses) {
2192344a3780SDimitry Andric     LLVM_DEBUG(dbgs() << "  Local use SU(" << LU->NodeNum << ") -> SU("
219359d6cff9SDimitry Andric                       << GlobalSU->NodeNum << ")\n");
2194344a3780SDimitry Andric     DAG->addEdge(GlobalSU, SDep(LU, SDep::Weak));
219559d6cff9SDimitry Andric   }
2196344a3780SDimitry Andric   for (SUnit *GU : GlobalUses) {
2197344a3780SDimitry Andric     LLVM_DEBUG(dbgs() << "  Global use SU(" << GU->NodeNum << ") -> SU("
219859d6cff9SDimitry Andric                       << FirstLocalSU->NodeNum << ")\n");
2199344a3780SDimitry Andric     DAG->addEdge(FirstLocalSU, SDep(GU, SDep::Weak));
220059d6cff9SDimitry Andric   }
220159d6cff9SDimitry Andric }
220259d6cff9SDimitry Andric 
2203eb11fae6SDimitry Andric /// Callback from DAG postProcessing to create weak edges to encourage
220459d6cff9SDimitry Andric /// copy elimination.
apply(ScheduleDAGInstrs * DAGInstrs)220501095a5dSDimitry Andric void CopyConstrain::apply(ScheduleDAGInstrs *DAGInstrs) {
220601095a5dSDimitry Andric   ScheduleDAGMI *DAG = static_cast<ScheduleDAGMI*>(DAGInstrs);
22075ca98fd9SDimitry Andric   assert(DAG->hasVRegLiveness() && "Expect VRegs with LiveIntervals");
22085ca98fd9SDimitry Andric 
220959d6cff9SDimitry Andric   MachineBasicBlock::iterator FirstPos = nextIfDebug(DAG->begin(), DAG->end());
221059d6cff9SDimitry Andric   if (FirstPos == DAG->end())
221159d6cff9SDimitry Andric     return;
221201095a5dSDimitry Andric   RegionBeginIdx = DAG->getLIS()->getInstructionIndex(*FirstPos);
221359d6cff9SDimitry Andric   RegionEndIdx = DAG->getLIS()->getInstructionIndex(
221401095a5dSDimitry Andric       *priorNonDebug(DAG->end(), DAG->begin()));
221559d6cff9SDimitry Andric 
221608bbd35aSDimitry Andric   for (SUnit &SU : DAG->SUnits) {
221708bbd35aSDimitry Andric     if (!SU.getInstr()->isCopy())
221859d6cff9SDimitry Andric       continue;
221959d6cff9SDimitry Andric 
222008bbd35aSDimitry Andric     constrainLocalCopy(&SU, static_cast<ScheduleDAGMILive*>(DAG));
222159d6cff9SDimitry Andric   }
222259d6cff9SDimitry Andric }
222359d6cff9SDimitry Andric 
222459d6cff9SDimitry Andric //===----------------------------------------------------------------------===//
22255ca98fd9SDimitry Andric // MachineSchedStrategy helpers used by GenericScheduler, GenericPostScheduler
22265ca98fd9SDimitry Andric // and possibly other custom schedulers.
222763faed5bSDimitry Andric //===----------------------------------------------------------------------===//
222863faed5bSDimitry Andric 
22295ca98fd9SDimitry Andric static const unsigned InvalidCycle = ~0U;
2230522600a2SDimitry Andric 
~SchedBoundary()22315ca98fd9SDimitry Andric SchedBoundary::~SchedBoundary() { delete HazardRec; }
2232522600a2SDimitry Andric 
2233044eb2f6SDimitry Andric /// Given a Count of resource usage and a Latency value, return true if a
2234044eb2f6SDimitry Andric /// SchedBoundary becomes resource limited.
2235e6d15924SDimitry Andric /// If we are checking after scheduling a node, we should return true when
2236e6d15924SDimitry Andric /// we just reach the resource limit.
checkResourceLimit(unsigned LFactor,unsigned Count,unsigned Latency,bool AfterSchedNode)2237044eb2f6SDimitry Andric static bool checkResourceLimit(unsigned LFactor, unsigned Count,
2238e6d15924SDimitry Andric                                unsigned Latency, bool AfterSchedNode) {
2239e6d15924SDimitry Andric   int ResCntFactor = (int)(Count - (Latency * LFactor));
2240e6d15924SDimitry Andric   if (AfterSchedNode)
2241e6d15924SDimitry Andric     return ResCntFactor >= (int)LFactor;
2242e6d15924SDimitry Andric   else
2243e6d15924SDimitry Andric     return ResCntFactor > (int)LFactor;
2244044eb2f6SDimitry Andric }
2245044eb2f6SDimitry Andric 
reset()22465ca98fd9SDimitry Andric void SchedBoundary::reset() {
22474a16efa3SDimitry Andric   // A new HazardRec is created for each DAG and owned by SchedBoundary.
2248f8af5cf6SDimitry Andric   // Destroying and reconstructing it is very expensive though. So keep
2249f8af5cf6SDimitry Andric   // invalid, placeholder HazardRecs.
2250f8af5cf6SDimitry Andric   if (HazardRec && HazardRec->isEnabled()) {
22514a16efa3SDimitry Andric     delete HazardRec;
22525ca98fd9SDimitry Andric     HazardRec = nullptr;
2253f8af5cf6SDimitry Andric   }
2254522600a2SDimitry Andric   Available.clear();
2255522600a2SDimitry Andric   Pending.clear();
2256522600a2SDimitry Andric   CheckPending = false;
2257522600a2SDimitry Andric   CurrCycle = 0;
2258f8af5cf6SDimitry Andric   CurrMOps = 0;
225971d5a254SDimitry Andric   MinReadyCycle = std::numeric_limits<unsigned>::max();
2260522600a2SDimitry Andric   ExpectedLatency = 0;
2261f8af5cf6SDimitry Andric   DependentLatency = 0;
2262f8af5cf6SDimitry Andric   RetiredMOps = 0;
2263f8af5cf6SDimitry Andric   MaxExecutedResCount = 0;
2264f8af5cf6SDimitry Andric   ZoneCritResIdx = 0;
2265522600a2SDimitry Andric   IsResourceLimited = false;
22665ca98fd9SDimitry Andric   ReservedCycles.clear();
22677fa27ce4SDimitry Andric   ReservedResourceSegments.clear();
2268e6d15924SDimitry Andric   ReservedCyclesIndex.clear();
2269344a3780SDimitry Andric   ResourceGroupSubUnitMasks.clear();
2270145449b1SDimitry Andric #if LLVM_ENABLE_ABI_BREAKING_CHECKS
22715ca98fd9SDimitry Andric   // Track the maximum number of stall cycles that could arise either from the
22725ca98fd9SDimitry Andric   // latency of a DAG edge or the number of cycles that a processor resource is
22735ca98fd9SDimitry Andric   // reserved (SchedBoundary::ReservedCycles).
22745ca98fd9SDimitry Andric   MaxObservedStall = 0;
2275522600a2SDimitry Andric #endif
2276522600a2SDimitry Andric   // Reserve a zero-count for invalid CritResIdx.
2277f8af5cf6SDimitry Andric   ExecutedResCounts.resize(1);
2278f8af5cf6SDimitry Andric   assert(!ExecutedResCounts[0] && "nonzero count for bad resource");
2279522600a2SDimitry Andric }
228058b69754SDimitry Andric 
22815ca98fd9SDimitry Andric void SchedRemainder::
init(ScheduleDAGMI * DAG,const TargetSchedModel * SchedModel)2282522600a2SDimitry Andric init(ScheduleDAGMI *DAG, const TargetSchedModel *SchedModel) {
2283522600a2SDimitry Andric   reset();
2284522600a2SDimitry Andric   if (!SchedModel->hasInstrSchedModel())
2285522600a2SDimitry Andric     return;
2286522600a2SDimitry Andric   RemainingCounts.resize(SchedModel->getNumProcResourceKinds());
228708bbd35aSDimitry Andric   for (SUnit &SU : DAG->SUnits) {
228808bbd35aSDimitry Andric     const MCSchedClassDesc *SC = DAG->getSchedClass(&SU);
228908bbd35aSDimitry Andric     RemIssueCount += SchedModel->getNumMicroOps(SU.getInstr(), SC)
2290f8af5cf6SDimitry Andric       * SchedModel->getMicroOpFactor();
2291522600a2SDimitry Andric     for (TargetSchedModel::ProcResIter
2292522600a2SDimitry Andric            PI = SchedModel->getWriteProcResBegin(SC),
2293522600a2SDimitry Andric            PE = SchedModel->getWriteProcResEnd(SC); PI != PE; ++PI) {
2294522600a2SDimitry Andric       unsigned PIdx = PI->ProcResourceIdx;
2295522600a2SDimitry Andric       unsigned Factor = SchedModel->getResourceFactor(PIdx);
2296b1c73532SDimitry Andric       assert(PI->ReleaseAtCycle >= PI->AcquireAtCycle);
2297b1c73532SDimitry Andric       RemainingCounts[PIdx] +=
2298b1c73532SDimitry Andric           (Factor * (PI->ReleaseAtCycle - PI->AcquireAtCycle));
2299522600a2SDimitry Andric     }
2300522600a2SDimitry Andric   }
2301522600a2SDimitry Andric }
2302522600a2SDimitry Andric 
23035ca98fd9SDimitry Andric void SchedBoundary::
init(ScheduleDAGMI * dag,const TargetSchedModel * smodel,SchedRemainder * rem)2304522600a2SDimitry Andric init(ScheduleDAGMI *dag, const TargetSchedModel *smodel, SchedRemainder *rem) {
2305522600a2SDimitry Andric   reset();
2306522600a2SDimitry Andric   DAG = dag;
2307522600a2SDimitry Andric   SchedModel = smodel;
2308522600a2SDimitry Andric   Rem = rem;
23095ca98fd9SDimitry Andric   if (SchedModel->hasInstrSchedModel()) {
2310e6d15924SDimitry Andric     unsigned ResourceCount = SchedModel->getNumProcResourceKinds();
2311e6d15924SDimitry Andric     ReservedCyclesIndex.resize(ResourceCount);
2312e6d15924SDimitry Andric     ExecutedResCounts.resize(ResourceCount);
2313344a3780SDimitry Andric     ResourceGroupSubUnitMasks.resize(ResourceCount, APInt(ResourceCount, 0));
2314e6d15924SDimitry Andric     unsigned NumUnits = 0;
2315e6d15924SDimitry Andric 
2316e6d15924SDimitry Andric     for (unsigned i = 0; i < ResourceCount; ++i) {
2317e6d15924SDimitry Andric       ReservedCyclesIndex[i] = NumUnits;
2318e6d15924SDimitry Andric       NumUnits += SchedModel->getProcResource(i)->NumUnits;
2319344a3780SDimitry Andric       if (isUnbufferedGroup(i)) {
2320344a3780SDimitry Andric         auto SubUnits = SchedModel->getProcResource(i)->SubUnitsIdxBegin;
2321344a3780SDimitry Andric         for (unsigned U = 0, UE = SchedModel->getProcResource(i)->NumUnits;
2322344a3780SDimitry Andric              U != UE; ++U)
2323344a3780SDimitry Andric           ResourceGroupSubUnitMasks[i].setBit(SubUnits[U]);
2324344a3780SDimitry Andric       }
2325e6d15924SDimitry Andric     }
2326e6d15924SDimitry Andric 
2327e6d15924SDimitry Andric     ReservedCycles.resize(NumUnits, InvalidCycle);
23285ca98fd9SDimitry Andric   }
23295ca98fd9SDimitry Andric }
23305ca98fd9SDimitry Andric 
23315ca98fd9SDimitry Andric /// Compute the stall cycles based on this SUnit's ready time. Heuristics treat
23325ca98fd9SDimitry Andric /// these "soft stalls" differently than the hard stall cycles based on CPU
23335ca98fd9SDimitry Andric /// resources and computed by checkHazard(). A fully in-order model
23345ca98fd9SDimitry Andric /// (MicroOpBufferSize==0) will not make use of this since instructions are not
23355ca98fd9SDimitry Andric /// available for scheduling until they are ready. However, a weaker in-order
23365ca98fd9SDimitry Andric /// model may use this for heuristics. For example, if a processor has in-order
23375ca98fd9SDimitry Andric /// behavior when reading certain resources, this may come into play.
getLatencyStallCycles(SUnit * SU)23385ca98fd9SDimitry Andric unsigned SchedBoundary::getLatencyStallCycles(SUnit *SU) {
23395ca98fd9SDimitry Andric   if (!SU->isUnbuffered)
23405ca98fd9SDimitry Andric     return 0;
23415ca98fd9SDimitry Andric 
23425ca98fd9SDimitry Andric   unsigned ReadyCycle = (isTop() ? SU->TopReadyCycle : SU->BotReadyCycle);
23435ca98fd9SDimitry Andric   if (ReadyCycle > CurrCycle)
23445ca98fd9SDimitry Andric     return ReadyCycle - CurrCycle;
23455ca98fd9SDimitry Andric   return 0;
23465ca98fd9SDimitry Andric }
23475ca98fd9SDimitry Andric 
2348e6d15924SDimitry Andric /// Compute the next cycle at which the given processor resource unit
2349e6d15924SDimitry Andric /// can be scheduled.
getNextResourceCycleByInstance(unsigned InstanceIdx,unsigned ReleaseAtCycle,unsigned AcquireAtCycle)2350e6d15924SDimitry Andric unsigned SchedBoundary::getNextResourceCycleByInstance(unsigned InstanceIdx,
2351b1c73532SDimitry Andric                                                        unsigned ReleaseAtCycle,
2352b1c73532SDimitry Andric                                                        unsigned AcquireAtCycle) {
23537fa27ce4SDimitry Andric   if (SchedModel && SchedModel->enableIntervals()) {
23547fa27ce4SDimitry Andric     if (isTop())
23557fa27ce4SDimitry Andric       return ReservedResourceSegments[InstanceIdx].getFirstAvailableAtFromTop(
2356b1c73532SDimitry Andric           CurrCycle, AcquireAtCycle, ReleaseAtCycle);
23577fa27ce4SDimitry Andric 
23587fa27ce4SDimitry Andric     return ReservedResourceSegments[InstanceIdx].getFirstAvailableAtFromBottom(
2359b1c73532SDimitry Andric         CurrCycle, AcquireAtCycle, ReleaseAtCycle);
23607fa27ce4SDimitry Andric   }
23617fa27ce4SDimitry Andric 
2362e6d15924SDimitry Andric   unsigned NextUnreserved = ReservedCycles[InstanceIdx];
23635ca98fd9SDimitry Andric   // If this resource has never been used, always return cycle zero.
23645ca98fd9SDimitry Andric   if (NextUnreserved == InvalidCycle)
23657fa27ce4SDimitry Andric     return CurrCycle;
23665ca98fd9SDimitry Andric   // For bottom-up scheduling add the cycles needed for the current operation.
23675ca98fd9SDimitry Andric   if (!isTop())
2368b1c73532SDimitry Andric     NextUnreserved = std::max(CurrCycle, NextUnreserved + ReleaseAtCycle);
23695ca98fd9SDimitry Andric   return NextUnreserved;
23705ca98fd9SDimitry Andric }
23715ca98fd9SDimitry Andric 
2372e6d15924SDimitry Andric /// Compute the next cycle at which the given processor resource can be
2373e6d15924SDimitry Andric /// scheduled.  Returns the next cycle and the index of the processor resource
2374e6d15924SDimitry Andric /// instance in the reserved cycles vector.
2375e6d15924SDimitry Andric std::pair<unsigned, unsigned>
getNextResourceCycle(const MCSchedClassDesc * SC,unsigned PIdx,unsigned ReleaseAtCycle,unsigned AcquireAtCycle)2376344a3780SDimitry Andric SchedBoundary::getNextResourceCycle(const MCSchedClassDesc *SC, unsigned PIdx,
2377b1c73532SDimitry Andric                                     unsigned ReleaseAtCycle,
2378b1c73532SDimitry Andric                                     unsigned AcquireAtCycle) {
23797fa27ce4SDimitry Andric   if (MischedDetailResourceBooking) {
23807fa27ce4SDimitry Andric     LLVM_DEBUG(dbgs() << "  Resource booking (@" << CurrCycle << "c): \n");
23817fa27ce4SDimitry Andric     LLVM_DEBUG(dumpReservedCycles());
23827fa27ce4SDimitry Andric     LLVM_DEBUG(dbgs() << "  getNextResourceCycle (@" << CurrCycle << "c): \n");
23837fa27ce4SDimitry Andric   }
2384e6d15924SDimitry Andric   unsigned MinNextUnreserved = InvalidCycle;
2385e6d15924SDimitry Andric   unsigned InstanceIdx = 0;
2386e6d15924SDimitry Andric   unsigned StartIndex = ReservedCyclesIndex[PIdx];
2387e6d15924SDimitry Andric   unsigned NumberOfInstances = SchedModel->getProcResource(PIdx)->NumUnits;
2388e6d15924SDimitry Andric   assert(NumberOfInstances > 0 &&
2389e6d15924SDimitry Andric          "Cannot have zero instances of a ProcResource");
2390e6d15924SDimitry Andric 
2391344a3780SDimitry Andric   if (isUnbufferedGroup(PIdx)) {
2392b1c73532SDimitry Andric     // If any subunits are used by the instruction, report that the
2393b1c73532SDimitry Andric     // subunits of the resource group are available at the first cycle
2394b1c73532SDimitry Andric     // in which the unit is available, effectively removing the group
2395b1c73532SDimitry Andric     // record from hazarding and basing the hazarding decisions on the
2396b1c73532SDimitry Andric     // subunit records. Otherwise, choose the first available instance
2397b1c73532SDimitry Andric     // from among the subunits.  Specifications which assign cycles to
2398b1c73532SDimitry Andric     // both the subunits and the group or which use an unbuffered
2399b1c73532SDimitry Andric     // group with buffered subunits will appear to schedule
2400b1c73532SDimitry Andric     // strangely. In the first case, the additional cycles for the
2401b1c73532SDimitry Andric     // group will be ignored.  In the second, the group will be
2402b1c73532SDimitry Andric     // ignored entirely.
2403344a3780SDimitry Andric     for (const MCWriteProcResEntry &PE :
2404344a3780SDimitry Andric          make_range(SchedModel->getWriteProcResBegin(SC),
2405344a3780SDimitry Andric                     SchedModel->getWriteProcResEnd(SC)))
2406344a3780SDimitry Andric       if (ResourceGroupSubUnitMasks[PIdx][PE.ProcResourceIdx])
2407b1c73532SDimitry Andric         return std::make_pair(getNextResourceCycleByInstance(
2408b1c73532SDimitry Andric                                   StartIndex, ReleaseAtCycle, AcquireAtCycle),
2409b1c73532SDimitry Andric                               StartIndex);
2410344a3780SDimitry Andric 
2411344a3780SDimitry Andric     auto SubUnits = SchedModel->getProcResource(PIdx)->SubUnitsIdxBegin;
2412344a3780SDimitry Andric     for (unsigned I = 0, End = NumberOfInstances; I < End; ++I) {
2413344a3780SDimitry Andric       unsigned NextUnreserved, NextInstanceIdx;
2414344a3780SDimitry Andric       std::tie(NextUnreserved, NextInstanceIdx) =
2415b1c73532SDimitry Andric           getNextResourceCycle(SC, SubUnits[I], ReleaseAtCycle, AcquireAtCycle);
2416344a3780SDimitry Andric       if (MinNextUnreserved > NextUnreserved) {
2417344a3780SDimitry Andric         InstanceIdx = NextInstanceIdx;
2418344a3780SDimitry Andric         MinNextUnreserved = NextUnreserved;
2419344a3780SDimitry Andric       }
2420344a3780SDimitry Andric     }
2421344a3780SDimitry Andric     return std::make_pair(MinNextUnreserved, InstanceIdx);
2422344a3780SDimitry Andric   }
2423344a3780SDimitry Andric 
2424e6d15924SDimitry Andric   for (unsigned I = StartIndex, End = StartIndex + NumberOfInstances; I < End;
2425e6d15924SDimitry Andric        ++I) {
24267fa27ce4SDimitry Andric     unsigned NextUnreserved =
2427b1c73532SDimitry Andric         getNextResourceCycleByInstance(I, ReleaseAtCycle, AcquireAtCycle);
24287fa27ce4SDimitry Andric     if (MischedDetailResourceBooking)
24297fa27ce4SDimitry Andric       LLVM_DEBUG(dbgs() << "    Instance " << I - StartIndex << " available @"
24307fa27ce4SDimitry Andric                         << NextUnreserved << "c\n");
2431e6d15924SDimitry Andric     if (MinNextUnreserved > NextUnreserved) {
2432e6d15924SDimitry Andric       InstanceIdx = I;
2433e6d15924SDimitry Andric       MinNextUnreserved = NextUnreserved;
2434e6d15924SDimitry Andric     }
2435e6d15924SDimitry Andric   }
24367fa27ce4SDimitry Andric   if (MischedDetailResourceBooking)
24377fa27ce4SDimitry Andric     LLVM_DEBUG(dbgs() << "    selecting " << SchedModel->getResourceName(PIdx)
24387fa27ce4SDimitry Andric                       << "[" << InstanceIdx - StartIndex << "]"
24397fa27ce4SDimitry Andric                       << " available @" << MinNextUnreserved << "c"
24407fa27ce4SDimitry Andric                       << "\n");
2441e6d15924SDimitry Andric   return std::make_pair(MinNextUnreserved, InstanceIdx);
2442e6d15924SDimitry Andric }
2443e6d15924SDimitry Andric 
24445ca98fd9SDimitry Andric /// Does this SU have a hazard within the current instruction group.
24455ca98fd9SDimitry Andric ///
24465ca98fd9SDimitry Andric /// The scheduler supports two modes of hazard recognition. The first is the
24475ca98fd9SDimitry Andric /// ScheduleHazardRecognizer API. It is a fully general hazard recognizer that
24485ca98fd9SDimitry Andric /// supports highly complicated in-order reservation tables
2449eb11fae6SDimitry Andric /// (ScoreboardHazardRecognizer) and arbitrary target-specific logic.
24505ca98fd9SDimitry Andric ///
24515ca98fd9SDimitry Andric /// The second is a streamlined mechanism that checks for hazards based on
24525ca98fd9SDimitry Andric /// simple counters that the scheduler itself maintains. It explicitly checks
24535ca98fd9SDimitry Andric /// for instruction dispatch limitations, including the number of micro-ops that
24545ca98fd9SDimitry Andric /// can dispatch per cycle.
24555ca98fd9SDimitry Andric ///
24565ca98fd9SDimitry Andric /// TODO: Also check whether the SU must start a new group.
checkHazard(SUnit * SU)24575ca98fd9SDimitry Andric bool SchedBoundary::checkHazard(SUnit *SU) {
24585ca98fd9SDimitry Andric   if (HazardRec->isEnabled()
24595ca98fd9SDimitry Andric       && HazardRec->getHazardType(SU) != ScheduleHazardRecognizer::NoHazard) {
24605ca98fd9SDimitry Andric     return true;
24615ca98fd9SDimitry Andric   }
246271d5a254SDimitry Andric 
24635ca98fd9SDimitry Andric   unsigned uops = SchedModel->getNumMicroOps(SU->getInstr());
24645ca98fd9SDimitry Andric   if ((CurrMOps > 0) && (CurrMOps + uops > SchedModel->getIssueWidth())) {
2465eb11fae6SDimitry Andric     LLVM_DEBUG(dbgs() << "  SU(" << SU->NodeNum << ") uops="
24665ca98fd9SDimitry Andric                       << SchedModel->getNumMicroOps(SU->getInstr()) << '\n');
24675ca98fd9SDimitry Andric     return true;
24685ca98fd9SDimitry Andric   }
246971d5a254SDimitry Andric 
247071d5a254SDimitry Andric   if (CurrMOps > 0 &&
247171d5a254SDimitry Andric       ((isTop() && SchedModel->mustBeginGroup(SU->getInstr())) ||
247271d5a254SDimitry Andric        (!isTop() && SchedModel->mustEndGroup(SU->getInstr())))) {
2473eb11fae6SDimitry Andric     LLVM_DEBUG(dbgs() << "  hazard: SU(" << SU->NodeNum << ") must "
247471d5a254SDimitry Andric                       << (isTop() ? "begin" : "end") << " group\n");
247571d5a254SDimitry Andric     return true;
247671d5a254SDimitry Andric   }
247771d5a254SDimitry Andric 
24785ca98fd9SDimitry Andric   if (SchedModel->hasInstrSchedModel() && SU->hasReservedResource) {
24795ca98fd9SDimitry Andric     const MCSchedClassDesc *SC = DAG->getSchedClass(SU);
2480044eb2f6SDimitry Andric     for (const MCWriteProcResEntry &PE :
2481044eb2f6SDimitry Andric           make_range(SchedModel->getWriteProcResBegin(SC),
2482044eb2f6SDimitry Andric                      SchedModel->getWriteProcResEnd(SC))) {
2483044eb2f6SDimitry Andric       unsigned ResIdx = PE.ProcResourceIdx;
2484b1c73532SDimitry Andric       unsigned ReleaseAtCycle = PE.ReleaseAtCycle;
2485b1c73532SDimitry Andric       unsigned AcquireAtCycle = PE.AcquireAtCycle;
2486e6d15924SDimitry Andric       unsigned NRCycle, InstanceIdx;
24877fa27ce4SDimitry Andric       std::tie(NRCycle, InstanceIdx) =
2488b1c73532SDimitry Andric           getNextResourceCycle(SC, ResIdx, ReleaseAtCycle, AcquireAtCycle);
24895ca98fd9SDimitry Andric       if (NRCycle > CurrCycle) {
2490145449b1SDimitry Andric #if LLVM_ENABLE_ABI_BREAKING_CHECKS
2491b1c73532SDimitry Andric         MaxObservedStall = std::max(ReleaseAtCycle, MaxObservedStall);
24925ca98fd9SDimitry Andric #endif
2493eb11fae6SDimitry Andric         LLVM_DEBUG(dbgs() << "  SU(" << SU->NodeNum << ") "
2494e6d15924SDimitry Andric                           << SchedModel->getResourceName(ResIdx)
2495e6d15924SDimitry Andric                           << '[' << InstanceIdx - ReservedCyclesIndex[ResIdx]  << ']'
2496e6d15924SDimitry Andric                           << "=" << NRCycle << "c\n");
24975ca98fd9SDimitry Andric         return true;
24985ca98fd9SDimitry Andric       }
24995ca98fd9SDimitry Andric     }
25005ca98fd9SDimitry Andric   }
25015ca98fd9SDimitry Andric   return false;
25025ca98fd9SDimitry Andric }
25035ca98fd9SDimitry Andric 
25045ca98fd9SDimitry Andric // Find the unscheduled node in ReadySUs with the highest latency.
25055ca98fd9SDimitry Andric unsigned SchedBoundary::
findMaxLatency(ArrayRef<SUnit * > ReadySUs)25065ca98fd9SDimitry Andric findMaxLatency(ArrayRef<SUnit*> ReadySUs) {
25075ca98fd9SDimitry Andric   SUnit *LateSU = nullptr;
25085ca98fd9SDimitry Andric   unsigned RemLatency = 0;
250908bbd35aSDimitry Andric   for (SUnit *SU : ReadySUs) {
251008bbd35aSDimitry Andric     unsigned L = getUnscheduledLatency(SU);
25115ca98fd9SDimitry Andric     if (L > RemLatency) {
25125ca98fd9SDimitry Andric       RemLatency = L;
251308bbd35aSDimitry Andric       LateSU = SU;
25145ca98fd9SDimitry Andric     }
25155ca98fd9SDimitry Andric   }
25165ca98fd9SDimitry Andric   if (LateSU) {
2517eb11fae6SDimitry Andric     LLVM_DEBUG(dbgs() << Available.getName() << " RemLatency SU("
25185ca98fd9SDimitry Andric                       << LateSU->NodeNum << ") " << RemLatency << "c\n");
25195ca98fd9SDimitry Andric   }
25205ca98fd9SDimitry Andric   return RemLatency;
25215ca98fd9SDimitry Andric }
25225ca98fd9SDimitry Andric 
25235ca98fd9SDimitry Andric // Count resources in this zone and the remaining unscheduled
25245ca98fd9SDimitry Andric // instruction. Return the max count, scaled. Set OtherCritIdx to the critical
25255ca98fd9SDimitry Andric // resource index, or zero if the zone is issue limited.
25265ca98fd9SDimitry Andric unsigned SchedBoundary::
getOtherResourceCount(unsigned & OtherCritIdx)25275ca98fd9SDimitry Andric getOtherResourceCount(unsigned &OtherCritIdx) {
25285ca98fd9SDimitry Andric   OtherCritIdx = 0;
25295ca98fd9SDimitry Andric   if (!SchedModel->hasInstrSchedModel())
25305ca98fd9SDimitry Andric     return 0;
25315ca98fd9SDimitry Andric 
25325ca98fd9SDimitry Andric   unsigned OtherCritCount = Rem->RemIssueCount
25335ca98fd9SDimitry Andric     + (RetiredMOps * SchedModel->getMicroOpFactor());
2534eb11fae6SDimitry Andric   LLVM_DEBUG(dbgs() << "  " << Available.getName() << " + Remain MOps: "
25355ca98fd9SDimitry Andric                     << OtherCritCount / SchedModel->getMicroOpFactor() << '\n');
25365ca98fd9SDimitry Andric   for (unsigned PIdx = 1, PEnd = SchedModel->getNumProcResourceKinds();
25375ca98fd9SDimitry Andric        PIdx != PEnd; ++PIdx) {
25385ca98fd9SDimitry Andric     unsigned OtherCount = getResourceCount(PIdx) + Rem->RemainingCounts[PIdx];
25395ca98fd9SDimitry Andric     if (OtherCount > OtherCritCount) {
25405ca98fd9SDimitry Andric       OtherCritCount = OtherCount;
25415ca98fd9SDimitry Andric       OtherCritIdx = PIdx;
25425ca98fd9SDimitry Andric     }
25435ca98fd9SDimitry Andric   }
25445ca98fd9SDimitry Andric   if (OtherCritIdx) {
2545eb11fae6SDimitry Andric     LLVM_DEBUG(
2546eb11fae6SDimitry Andric         dbgs() << "  " << Available.getName() << " + Remain CritRes: "
25475ca98fd9SDimitry Andric                << OtherCritCount / SchedModel->getResourceFactor(OtherCritIdx)
25485ca98fd9SDimitry Andric                << " " << SchedModel->getResourceName(OtherCritIdx) << "\n");
25495ca98fd9SDimitry Andric   }
25505ca98fd9SDimitry Andric   return OtherCritCount;
25515ca98fd9SDimitry Andric }
25525ca98fd9SDimitry Andric 
releaseNode(SUnit * SU,unsigned ReadyCycle,bool InPQueue,unsigned Idx)2553706b4fc4SDimitry Andric void SchedBoundary::releaseNode(SUnit *SU, unsigned ReadyCycle, bool InPQueue,
2554706b4fc4SDimitry Andric                                 unsigned Idx) {
25555ca98fd9SDimitry Andric   assert(SU->getInstr() && "Scheduled SUnit must have instr");
25565ca98fd9SDimitry Andric 
2557145449b1SDimitry Andric #if LLVM_ENABLE_ABI_BREAKING_CHECKS
25585ca98fd9SDimitry Andric   // ReadyCycle was been bumped up to the CurrCycle when this node was
25595ca98fd9SDimitry Andric   // scheduled, but CurrCycle may have been eagerly advanced immediately after
25605ca98fd9SDimitry Andric   // scheduling, so may now be greater than ReadyCycle.
25615ca98fd9SDimitry Andric   if (ReadyCycle > CurrCycle)
25625ca98fd9SDimitry Andric     MaxObservedStall = std::max(ReadyCycle - CurrCycle, MaxObservedStall);
25635ca98fd9SDimitry Andric #endif
25645ca98fd9SDimitry Andric 
25655ca98fd9SDimitry Andric   if (ReadyCycle < MinReadyCycle)
25665ca98fd9SDimitry Andric     MinReadyCycle = ReadyCycle;
25675ca98fd9SDimitry Andric 
25685ca98fd9SDimitry Andric   // Check for interlocks first. For the purpose of other heuristics, an
25695ca98fd9SDimitry Andric   // instruction that cannot issue appears as if it's not in the ReadyQueue.
25705ca98fd9SDimitry Andric   bool IsBuffered = SchedModel->getMicroOpBufferSize() != 0;
2571706b4fc4SDimitry Andric   bool HazardDetected = (!IsBuffered && ReadyCycle > CurrCycle) ||
2572706b4fc4SDimitry Andric                         checkHazard(SU) || (Available.size() >= ReadyListLimit);
2573706b4fc4SDimitry Andric 
2574706b4fc4SDimitry Andric   if (!HazardDetected) {
25755ca98fd9SDimitry Andric     Available.push(SU);
2576706b4fc4SDimitry Andric 
2577706b4fc4SDimitry Andric     if (InPQueue)
2578706b4fc4SDimitry Andric       Pending.remove(Pending.begin() + Idx);
2579706b4fc4SDimitry Andric     return;
2580706b4fc4SDimitry Andric   }
2581706b4fc4SDimitry Andric 
2582706b4fc4SDimitry Andric   if (!InPQueue)
2583706b4fc4SDimitry Andric     Pending.push(SU);
25845ca98fd9SDimitry Andric }
25855ca98fd9SDimitry Andric 
25865ca98fd9SDimitry Andric /// Move the boundary of scheduled code by one cycle.
bumpCycle(unsigned NextCycle)25875ca98fd9SDimitry Andric void SchedBoundary::bumpCycle(unsigned NextCycle) {
25885ca98fd9SDimitry Andric   if (SchedModel->getMicroOpBufferSize() == 0) {
258971d5a254SDimitry Andric     assert(MinReadyCycle < std::numeric_limits<unsigned>::max() &&
259071d5a254SDimitry Andric            "MinReadyCycle uninitialized");
25915ca98fd9SDimitry Andric     if (MinReadyCycle > NextCycle)
25925ca98fd9SDimitry Andric       NextCycle = MinReadyCycle;
25935ca98fd9SDimitry Andric   }
25945ca98fd9SDimitry Andric   // Update the current micro-ops, which will issue in the next cycle.
25955ca98fd9SDimitry Andric   unsigned DecMOps = SchedModel->getIssueWidth() * (NextCycle - CurrCycle);
25965ca98fd9SDimitry Andric   CurrMOps = (CurrMOps <= DecMOps) ? 0 : CurrMOps - DecMOps;
25975ca98fd9SDimitry Andric 
25985ca98fd9SDimitry Andric   // Decrement DependentLatency based on the next cycle.
25995ca98fd9SDimitry Andric   if ((NextCycle - CurrCycle) > DependentLatency)
26005ca98fd9SDimitry Andric     DependentLatency = 0;
26015ca98fd9SDimitry Andric   else
26025ca98fd9SDimitry Andric     DependentLatency -= (NextCycle - CurrCycle);
26035ca98fd9SDimitry Andric 
26045ca98fd9SDimitry Andric   if (!HazardRec->isEnabled()) {
26055ca98fd9SDimitry Andric     // Bypass HazardRec virtual calls.
26065ca98fd9SDimitry Andric     CurrCycle = NextCycle;
260701095a5dSDimitry Andric   } else {
26085ca98fd9SDimitry Andric     // Bypass getHazardType calls in case of long latency.
26095ca98fd9SDimitry Andric     for (; CurrCycle != NextCycle; ++CurrCycle) {
26105ca98fd9SDimitry Andric       if (isTop())
26115ca98fd9SDimitry Andric         HazardRec->AdvanceCycle();
26125ca98fd9SDimitry Andric       else
26135ca98fd9SDimitry Andric         HazardRec->RecedeCycle();
26145ca98fd9SDimitry Andric     }
26155ca98fd9SDimitry Andric   }
26165ca98fd9SDimitry Andric   CheckPending = true;
26175ca98fd9SDimitry Andric   IsResourceLimited =
2618044eb2f6SDimitry Andric       checkResourceLimit(SchedModel->getLatencyFactor(), getCriticalCount(),
2619e6d15924SDimitry Andric                          getScheduledLatency(), true);
26205ca98fd9SDimitry Andric 
2621eb11fae6SDimitry Andric   LLVM_DEBUG(dbgs() << "Cycle: " << CurrCycle << ' ' << Available.getName()
2622eb11fae6SDimitry Andric                     << '\n');
26235ca98fd9SDimitry Andric }
26245ca98fd9SDimitry Andric 
incExecutedResources(unsigned PIdx,unsigned Count)26255ca98fd9SDimitry Andric void SchedBoundary::incExecutedResources(unsigned PIdx, unsigned Count) {
26265ca98fd9SDimitry Andric   ExecutedResCounts[PIdx] += Count;
26275ca98fd9SDimitry Andric   if (ExecutedResCounts[PIdx] > MaxExecutedResCount)
26285ca98fd9SDimitry Andric     MaxExecutedResCount = ExecutedResCounts[PIdx];
26295ca98fd9SDimitry Andric }
26305ca98fd9SDimitry Andric 
26315ca98fd9SDimitry Andric /// Add the given processor resource to this scheduled zone.
26325ca98fd9SDimitry Andric ///
2633b1c73532SDimitry Andric /// \param ReleaseAtCycle indicates the number of consecutive (non-pipelined)
2634b1c73532SDimitry Andric /// cycles during which this resource is released.
2635b1c73532SDimitry Andric ///
2636b1c73532SDimitry Andric /// \param AcquireAtCycle indicates the number of consecutive (non-pipelined)
2637b1c73532SDimitry Andric /// cycles at which the resource is aquired after issue (assuming no stalls).
26385ca98fd9SDimitry Andric ///
26395ca98fd9SDimitry Andric /// \return the next cycle at which the instruction may execute without
26405ca98fd9SDimitry Andric /// oversubscribing resources.
countResource(const MCSchedClassDesc * SC,unsigned PIdx,unsigned ReleaseAtCycle,unsigned NextCycle,unsigned AcquireAtCycle)2641344a3780SDimitry Andric unsigned SchedBoundary::countResource(const MCSchedClassDesc *SC, unsigned PIdx,
2642b1c73532SDimitry Andric                                       unsigned ReleaseAtCycle,
2643b1c73532SDimitry Andric                                       unsigned NextCycle,
2644b1c73532SDimitry Andric                                       unsigned AcquireAtCycle) {
26455ca98fd9SDimitry Andric   unsigned Factor = SchedModel->getResourceFactor(PIdx);
2646b1c73532SDimitry Andric   unsigned Count = Factor * (ReleaseAtCycle- AcquireAtCycle);
2647eb11fae6SDimitry Andric   LLVM_DEBUG(dbgs() << "  " << SchedModel->getResourceName(PIdx) << " +"
2648b1c73532SDimitry Andric                     << ReleaseAtCycle << "x" << Factor << "u\n");
26495ca98fd9SDimitry Andric 
26505ca98fd9SDimitry Andric   // Update Executed resources counts.
26515ca98fd9SDimitry Andric   incExecutedResources(PIdx, Count);
26525ca98fd9SDimitry Andric   assert(Rem->RemainingCounts[PIdx] >= Count && "resource double counted");
26535ca98fd9SDimitry Andric   Rem->RemainingCounts[PIdx] -= Count;
26545ca98fd9SDimitry Andric 
26555ca98fd9SDimitry Andric   // Check if this resource exceeds the current critical resource. If so, it
26565ca98fd9SDimitry Andric   // becomes the critical resource.
26575ca98fd9SDimitry Andric   if (ZoneCritResIdx != PIdx && (getResourceCount(PIdx) > getCriticalCount())) {
26585ca98fd9SDimitry Andric     ZoneCritResIdx = PIdx;
2659eb11fae6SDimitry Andric     LLVM_DEBUG(dbgs() << "  *** Critical resource "
26605ca98fd9SDimitry Andric                       << SchedModel->getResourceName(PIdx) << ": "
2661eb11fae6SDimitry Andric                       << getResourceCount(PIdx) / SchedModel->getLatencyFactor()
2662eb11fae6SDimitry Andric                       << "c\n");
26635ca98fd9SDimitry Andric   }
26645ca98fd9SDimitry Andric   // For reserved resources, record the highest cycle using the resource.
2665e6d15924SDimitry Andric   unsigned NextAvailable, InstanceIdx;
26667fa27ce4SDimitry Andric   std::tie(NextAvailable, InstanceIdx) =
2667b1c73532SDimitry Andric       getNextResourceCycle(SC, PIdx, ReleaseAtCycle, AcquireAtCycle);
26685ca98fd9SDimitry Andric   if (NextAvailable > CurrCycle) {
2669eb11fae6SDimitry Andric     LLVM_DEBUG(dbgs() << "  Resource conflict: "
2670e6d15924SDimitry Andric                       << SchedModel->getResourceName(PIdx)
2671e6d15924SDimitry Andric                       << '[' << InstanceIdx - ReservedCyclesIndex[PIdx]  << ']'
2672eb11fae6SDimitry Andric                       << " reserved until @" << NextAvailable << "\n");
26735ca98fd9SDimitry Andric   }
26745ca98fd9SDimitry Andric   return NextAvailable;
26755ca98fd9SDimitry Andric }
26765ca98fd9SDimitry Andric 
26775ca98fd9SDimitry Andric /// Move the boundary of scheduled code by one SUnit.
bumpNode(SUnit * SU)26785ca98fd9SDimitry Andric void SchedBoundary::bumpNode(SUnit *SU) {
26795ca98fd9SDimitry Andric   // Update the reservation table.
26805ca98fd9SDimitry Andric   if (HazardRec->isEnabled()) {
26815ca98fd9SDimitry Andric     if (!isTop() && SU->isCall) {
26825ca98fd9SDimitry Andric       // Calls are scheduled with their preceding instructions. For bottom-up
26835ca98fd9SDimitry Andric       // scheduling, clear the pipeline state before emitting.
26845ca98fd9SDimitry Andric       HazardRec->Reset();
26855ca98fd9SDimitry Andric     }
26865ca98fd9SDimitry Andric     HazardRec->EmitInstruction(SU);
2687e6d15924SDimitry Andric     // Scheduling an instruction may have made pending instructions available.
2688e6d15924SDimitry Andric     CheckPending = true;
26895ca98fd9SDimitry Andric   }
26905ca98fd9SDimitry Andric   // checkHazard should prevent scheduling multiple instructions per cycle that
26915ca98fd9SDimitry Andric   // exceed the issue width.
26925ca98fd9SDimitry Andric   const MCSchedClassDesc *SC = DAG->getSchedClass(SU);
26935ca98fd9SDimitry Andric   unsigned IncMOps = SchedModel->getNumMicroOps(SU->getInstr());
26945ca98fd9SDimitry Andric   assert(
26955ca98fd9SDimitry Andric       (CurrMOps == 0 || (CurrMOps + IncMOps) <= SchedModel->getIssueWidth()) &&
26965ca98fd9SDimitry Andric       "Cannot schedule this instruction's MicroOps in the current cycle.");
26975ca98fd9SDimitry Andric 
26985ca98fd9SDimitry Andric   unsigned ReadyCycle = (isTop() ? SU->TopReadyCycle : SU->BotReadyCycle);
2699eb11fae6SDimitry Andric   LLVM_DEBUG(dbgs() << "  Ready @" << ReadyCycle << "c\n");
27005ca98fd9SDimitry Andric 
27015ca98fd9SDimitry Andric   unsigned NextCycle = CurrCycle;
27025ca98fd9SDimitry Andric   switch (SchedModel->getMicroOpBufferSize()) {
27035ca98fd9SDimitry Andric   case 0:
27045ca98fd9SDimitry Andric     assert(ReadyCycle <= CurrCycle && "Broken PendingQueue");
27055ca98fd9SDimitry Andric     break;
27065ca98fd9SDimitry Andric   case 1:
27075ca98fd9SDimitry Andric     if (ReadyCycle > NextCycle) {
27085ca98fd9SDimitry Andric       NextCycle = ReadyCycle;
2709eb11fae6SDimitry Andric       LLVM_DEBUG(dbgs() << "  *** Stall until: " << ReadyCycle << "\n");
27105ca98fd9SDimitry Andric     }
27115ca98fd9SDimitry Andric     break;
27125ca98fd9SDimitry Andric   default:
27135ca98fd9SDimitry Andric     // We don't currently model the OOO reorder buffer, so consider all
27145ca98fd9SDimitry Andric     // scheduled MOps to be "retired". We do loosely model in-order resource
27155ca98fd9SDimitry Andric     // latency. If this instruction uses an in-order resource, account for any
27165ca98fd9SDimitry Andric     // likely stall cycles.
27175ca98fd9SDimitry Andric     if (SU->isUnbuffered && ReadyCycle > NextCycle)
27185ca98fd9SDimitry Andric       NextCycle = ReadyCycle;
27195ca98fd9SDimitry Andric     break;
27205ca98fd9SDimitry Andric   }
27215ca98fd9SDimitry Andric   RetiredMOps += IncMOps;
27225ca98fd9SDimitry Andric 
27235ca98fd9SDimitry Andric   // Update resource counts and critical resource.
27245ca98fd9SDimitry Andric   if (SchedModel->hasInstrSchedModel()) {
27255ca98fd9SDimitry Andric     unsigned DecRemIssue = IncMOps * SchedModel->getMicroOpFactor();
27265ca98fd9SDimitry Andric     assert(Rem->RemIssueCount >= DecRemIssue && "MOps double counted");
27275ca98fd9SDimitry Andric     Rem->RemIssueCount -= DecRemIssue;
27285ca98fd9SDimitry Andric     if (ZoneCritResIdx) {
27295ca98fd9SDimitry Andric       // Scale scheduled micro-ops for comparing with the critical resource.
27305ca98fd9SDimitry Andric       unsigned ScaledMOps =
27315ca98fd9SDimitry Andric         RetiredMOps * SchedModel->getMicroOpFactor();
27325ca98fd9SDimitry Andric 
27335ca98fd9SDimitry Andric       // If scaled micro-ops are now more than the previous critical resource by
27345ca98fd9SDimitry Andric       // a full cycle, then micro-ops issue becomes critical.
27355ca98fd9SDimitry Andric       if ((int)(ScaledMOps - getResourceCount(ZoneCritResIdx))
27365ca98fd9SDimitry Andric           >= (int)SchedModel->getLatencyFactor()) {
27375ca98fd9SDimitry Andric         ZoneCritResIdx = 0;
2738eb11fae6SDimitry Andric         LLVM_DEBUG(dbgs() << "  *** Critical resource NumMicroOps: "
2739eb11fae6SDimitry Andric                           << ScaledMOps / SchedModel->getLatencyFactor()
2740eb11fae6SDimitry Andric                           << "c\n");
27415ca98fd9SDimitry Andric       }
27425ca98fd9SDimitry Andric     }
27435ca98fd9SDimitry Andric     for (TargetSchedModel::ProcResIter
27445ca98fd9SDimitry Andric            PI = SchedModel->getWriteProcResBegin(SC),
27455ca98fd9SDimitry Andric            PE = SchedModel->getWriteProcResEnd(SC); PI != PE; ++PI) {
2746b1c73532SDimitry Andric       unsigned RCycle =
2747b1c73532SDimitry Andric           countResource(SC, PI->ProcResourceIdx, PI->ReleaseAtCycle, NextCycle,
2748b1c73532SDimitry Andric                         PI->AcquireAtCycle);
27495ca98fd9SDimitry Andric       if (RCycle > NextCycle)
27505ca98fd9SDimitry Andric         NextCycle = RCycle;
27515ca98fd9SDimitry Andric     }
27525ca98fd9SDimitry Andric     if (SU->hasReservedResource) {
27535ca98fd9SDimitry Andric       // For reserved resources, record the highest cycle using the resource.
27545ca98fd9SDimitry Andric       // For top-down scheduling, this is the cycle in which we schedule this
27555ca98fd9SDimitry Andric       // instruction plus the number of cycles the operations reserves the
27565ca98fd9SDimitry Andric       // resource. For bottom-up is it simply the instruction's cycle.
27575ca98fd9SDimitry Andric       for (TargetSchedModel::ProcResIter
27585ca98fd9SDimitry Andric              PI = SchedModel->getWriteProcResBegin(SC),
27595ca98fd9SDimitry Andric              PE = SchedModel->getWriteProcResEnd(SC); PI != PE; ++PI) {
27605ca98fd9SDimitry Andric         unsigned PIdx = PI->ProcResourceIdx;
27615ca98fd9SDimitry Andric         if (SchedModel->getProcResource(PIdx)->BufferSize == 0) {
27627fa27ce4SDimitry Andric 
27637fa27ce4SDimitry Andric           if (SchedModel && SchedModel->enableIntervals()) {
2764e6d15924SDimitry Andric             unsigned ReservedUntil, InstanceIdx;
2765b1c73532SDimitry Andric             std::tie(ReservedUntil, InstanceIdx) = getNextResourceCycle(
2766b1c73532SDimitry Andric                 SC, PIdx, PI->ReleaseAtCycle, PI->AcquireAtCycle);
27677fa27ce4SDimitry Andric             if (isTop()) {
27687fa27ce4SDimitry Andric               ReservedResourceSegments[InstanceIdx].add(
27697fa27ce4SDimitry Andric                   ResourceSegments::getResourceIntervalTop(
2770b1c73532SDimitry Andric                       NextCycle, PI->AcquireAtCycle, PI->ReleaseAtCycle),
27717fa27ce4SDimitry Andric                   MIResourceCutOff);
27727fa27ce4SDimitry Andric             } else {
27737fa27ce4SDimitry Andric               ReservedResourceSegments[InstanceIdx].add(
27747fa27ce4SDimitry Andric                   ResourceSegments::getResourceIntervalBottom(
2775b1c73532SDimitry Andric                       NextCycle, PI->AcquireAtCycle, PI->ReleaseAtCycle),
27767fa27ce4SDimitry Andric                   MIResourceCutOff);
27777fa27ce4SDimitry Andric             }
27787fa27ce4SDimitry Andric           } else {
27797fa27ce4SDimitry Andric 
27807fa27ce4SDimitry Andric             unsigned ReservedUntil, InstanceIdx;
2781b1c73532SDimitry Andric             std::tie(ReservedUntil, InstanceIdx) = getNextResourceCycle(
2782b1c73532SDimitry Andric                 SC, PIdx, PI->ReleaseAtCycle, PI->AcquireAtCycle);
27835ca98fd9SDimitry Andric             if (isTop()) {
2784e6d15924SDimitry Andric               ReservedCycles[InstanceIdx] =
2785b1c73532SDimitry Andric                   std::max(ReservedUntil, NextCycle + PI->ReleaseAtCycle);
2786e6d15924SDimitry Andric             } else
2787e6d15924SDimitry Andric               ReservedCycles[InstanceIdx] = NextCycle;
27885ca98fd9SDimitry Andric           }
27895ca98fd9SDimitry Andric         }
27905ca98fd9SDimitry Andric       }
27915ca98fd9SDimitry Andric     }
27927fa27ce4SDimitry Andric   }
27935ca98fd9SDimitry Andric   // Update ExpectedLatency and DependentLatency.
27945ca98fd9SDimitry Andric   unsigned &TopLatency = isTop() ? ExpectedLatency : DependentLatency;
27955ca98fd9SDimitry Andric   unsigned &BotLatency = isTop() ? DependentLatency : ExpectedLatency;
27965ca98fd9SDimitry Andric   if (SU->getDepth() > TopLatency) {
27975ca98fd9SDimitry Andric     TopLatency = SU->getDepth();
2798eb11fae6SDimitry Andric     LLVM_DEBUG(dbgs() << "  " << Available.getName() << " TopLatency SU("
2799eb11fae6SDimitry Andric                       << SU->NodeNum << ") " << TopLatency << "c\n");
28005ca98fd9SDimitry Andric   }
28015ca98fd9SDimitry Andric   if (SU->getHeight() > BotLatency) {
28025ca98fd9SDimitry Andric     BotLatency = SU->getHeight();
2803eb11fae6SDimitry Andric     LLVM_DEBUG(dbgs() << "  " << Available.getName() << " BotLatency SU("
2804eb11fae6SDimitry Andric                       << SU->NodeNum << ") " << BotLatency << "c\n");
28055ca98fd9SDimitry Andric   }
28065ca98fd9SDimitry Andric   // If we stall for any reason, bump the cycle.
2807044eb2f6SDimitry Andric   if (NextCycle > CurrCycle)
28085ca98fd9SDimitry Andric     bumpCycle(NextCycle);
2809044eb2f6SDimitry Andric   else
28105ca98fd9SDimitry Andric     // After updating ZoneCritResIdx and ExpectedLatency, check if we're
28115ca98fd9SDimitry Andric     // resource limited. If a stall occurred, bumpCycle does this.
28125ca98fd9SDimitry Andric     IsResourceLimited =
2813044eb2f6SDimitry Andric         checkResourceLimit(SchedModel->getLatencyFactor(), getCriticalCount(),
2814e6d15924SDimitry Andric                            getScheduledLatency(), true);
2815044eb2f6SDimitry Andric 
28165ca98fd9SDimitry Andric   // Update CurrMOps after calling bumpCycle to handle stalls, since bumpCycle
28175ca98fd9SDimitry Andric   // resets CurrMOps. Loop to handle instructions with more MOps than issue in
28185ca98fd9SDimitry Andric   // one cycle.  Since we commonly reach the max MOps here, opportunistically
28195ca98fd9SDimitry Andric   // bump the cycle to avoid uselessly checking everything in the readyQ.
28205ca98fd9SDimitry Andric   CurrMOps += IncMOps;
282171d5a254SDimitry Andric 
282271d5a254SDimitry Andric   // Bump the cycle count for issue group constraints.
282371d5a254SDimitry Andric   // This must be done after NextCycle has been adjust for all other stalls.
282471d5a254SDimitry Andric   // Calling bumpCycle(X) will reduce CurrMOps by one issue group and set
282571d5a254SDimitry Andric   // currCycle to X.
282671d5a254SDimitry Andric   if ((isTop() &&  SchedModel->mustEndGroup(SU->getInstr())) ||
282771d5a254SDimitry Andric       (!isTop() && SchedModel->mustBeginGroup(SU->getInstr()))) {
2828eb11fae6SDimitry Andric     LLVM_DEBUG(dbgs() << "  Bump cycle to " << (isTop() ? "end" : "begin")
2829eb11fae6SDimitry Andric                       << " group\n");
283071d5a254SDimitry Andric     bumpCycle(++NextCycle);
283171d5a254SDimitry Andric   }
283271d5a254SDimitry Andric 
28335ca98fd9SDimitry Andric   while (CurrMOps >= SchedModel->getIssueWidth()) {
2834eb11fae6SDimitry Andric     LLVM_DEBUG(dbgs() << "  *** Max MOps " << CurrMOps << " at cycle "
2835eb11fae6SDimitry Andric                       << CurrCycle << '\n');
28365ca98fd9SDimitry Andric     bumpCycle(++NextCycle);
28375ca98fd9SDimitry Andric   }
2838eb11fae6SDimitry Andric   LLVM_DEBUG(dumpScheduledState());
28395ca98fd9SDimitry Andric }
28405ca98fd9SDimitry Andric 
28415ca98fd9SDimitry Andric /// Release pending ready nodes in to the available queue. This makes them
28425ca98fd9SDimitry Andric /// visible to heuristics.
releasePending()28435ca98fd9SDimitry Andric void SchedBoundary::releasePending() {
28445ca98fd9SDimitry Andric   // If the available queue is empty, it is safe to reset MinReadyCycle.
28455ca98fd9SDimitry Andric   if (Available.empty())
284671d5a254SDimitry Andric     MinReadyCycle = std::numeric_limits<unsigned>::max();
28475ca98fd9SDimitry Andric 
28485ca98fd9SDimitry Andric   // Check to see if any of the pending instructions are ready to issue.  If
28495ca98fd9SDimitry Andric   // so, add them to the available queue.
2850706b4fc4SDimitry Andric   for (unsigned I = 0, E = Pending.size(); I < E; ++I) {
2851706b4fc4SDimitry Andric     SUnit *SU = *(Pending.begin() + I);
28525ca98fd9SDimitry Andric     unsigned ReadyCycle = isTop() ? SU->TopReadyCycle : SU->BotReadyCycle;
28535ca98fd9SDimitry Andric 
28545ca98fd9SDimitry Andric     if (ReadyCycle < MinReadyCycle)
28555ca98fd9SDimitry Andric       MinReadyCycle = ReadyCycle;
28565ca98fd9SDimitry Andric 
285701095a5dSDimitry Andric     if (Available.size() >= ReadyListLimit)
285801095a5dSDimitry Andric       break;
285901095a5dSDimitry Andric 
2860706b4fc4SDimitry Andric     releaseNode(SU, ReadyCycle, true, I);
2861706b4fc4SDimitry Andric     if (E != Pending.size()) {
2862706b4fc4SDimitry Andric       --I;
2863706b4fc4SDimitry Andric       --E;
2864706b4fc4SDimitry Andric     }
28655ca98fd9SDimitry Andric   }
28665ca98fd9SDimitry Andric   CheckPending = false;
28675ca98fd9SDimitry Andric }
28685ca98fd9SDimitry Andric 
28695ca98fd9SDimitry Andric /// Remove SU from the ready set for this boundary.
removeReady(SUnit * SU)28705ca98fd9SDimitry Andric void SchedBoundary::removeReady(SUnit *SU) {
28715ca98fd9SDimitry Andric   if (Available.isInQueue(SU))
28725ca98fd9SDimitry Andric     Available.remove(Available.find(SU));
28735ca98fd9SDimitry Andric   else {
28745ca98fd9SDimitry Andric     assert(Pending.isInQueue(SU) && "bad ready count");
28755ca98fd9SDimitry Andric     Pending.remove(Pending.find(SU));
28765ca98fd9SDimitry Andric   }
28775ca98fd9SDimitry Andric }
28785ca98fd9SDimitry Andric 
28795ca98fd9SDimitry Andric /// If this queue only has one ready candidate, return it. As a side effect,
28805ca98fd9SDimitry Andric /// defer any nodes that now hit a hazard, and advance the cycle until at least
28815ca98fd9SDimitry Andric /// one node is ready. If multiple instructions are ready, return NULL.
pickOnlyChoice()28825ca98fd9SDimitry Andric SUnit *SchedBoundary::pickOnlyChoice() {
28835ca98fd9SDimitry Andric   if (CheckPending)
28845ca98fd9SDimitry Andric     releasePending();
28855ca98fd9SDimitry Andric 
28865ca98fd9SDimitry Andric   // Defer any ready instrs that now have a hazard.
28875ca98fd9SDimitry Andric   for (ReadyQueue::iterator I = Available.begin(); I != Available.end();) {
28885ca98fd9SDimitry Andric     if (checkHazard(*I)) {
28895ca98fd9SDimitry Andric       Pending.push(*I);
28905ca98fd9SDimitry Andric       I = Available.remove(I);
28915ca98fd9SDimitry Andric       continue;
28925ca98fd9SDimitry Andric     }
28935ca98fd9SDimitry Andric     ++I;
28945ca98fd9SDimitry Andric   }
28955ca98fd9SDimitry Andric   for (unsigned i = 0; Available.empty(); ++i) {
28965ca98fd9SDimitry Andric //  FIXME: Re-enable assert once PR20057 is resolved.
28975ca98fd9SDimitry Andric //    assert(i <= (HazardRec->getMaxLookAhead() + MaxObservedStall) &&
28985ca98fd9SDimitry Andric //           "permanent hazard");
28995ca98fd9SDimitry Andric     (void)i;
29005ca98fd9SDimitry Andric     bumpCycle(CurrCycle + 1);
29015ca98fd9SDimitry Andric     releasePending();
29025ca98fd9SDimitry Andric   }
290301095a5dSDimitry Andric 
2904eb11fae6SDimitry Andric   LLVM_DEBUG(Pending.dump());
2905eb11fae6SDimitry Andric   LLVM_DEBUG(Available.dump());
290601095a5dSDimitry Andric 
29075ca98fd9SDimitry Andric   if (Available.size() == 1)
29085ca98fd9SDimitry Andric     return *Available.begin();
29095ca98fd9SDimitry Andric   return nullptr;
29105ca98fd9SDimitry Andric }
29115ca98fd9SDimitry Andric 
291271d5a254SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
2913e3b55780SDimitry Andric 
2914e3b55780SDimitry Andric /// Dump the content of the \ref ReservedCycles vector for the
2915e3b55780SDimitry Andric /// resources that are used in the basic block.
2916e3b55780SDimitry Andric ///
dumpReservedCycles() const2917e3b55780SDimitry Andric LLVM_DUMP_METHOD void SchedBoundary::dumpReservedCycles() const {
2918e3b55780SDimitry Andric   if (!SchedModel->hasInstrSchedModel())
2919e3b55780SDimitry Andric     return;
2920e3b55780SDimitry Andric 
2921e3b55780SDimitry Andric   unsigned ResourceCount = SchedModel->getNumProcResourceKinds();
2922e3b55780SDimitry Andric   unsigned StartIdx = 0;
2923e3b55780SDimitry Andric 
2924e3b55780SDimitry Andric   for (unsigned ResIdx = 0; ResIdx < ResourceCount; ++ResIdx) {
2925e3b55780SDimitry Andric     const unsigned NumUnits = SchedModel->getProcResource(ResIdx)->NumUnits;
2926e3b55780SDimitry Andric     std::string ResName = SchedModel->getResourceName(ResIdx);
2927e3b55780SDimitry Andric     for (unsigned UnitIdx = 0; UnitIdx < NumUnits; ++UnitIdx) {
29287fa27ce4SDimitry Andric       dbgs() << ResName << "(" << UnitIdx << ") = ";
29297fa27ce4SDimitry Andric       if (SchedModel && SchedModel->enableIntervals()) {
29307fa27ce4SDimitry Andric         if (ReservedResourceSegments.count(StartIdx + UnitIdx))
29317fa27ce4SDimitry Andric           dbgs() << ReservedResourceSegments.at(StartIdx + UnitIdx);
29327fa27ce4SDimitry Andric         else
29337fa27ce4SDimitry Andric           dbgs() << "{ }\n";
29347fa27ce4SDimitry Andric       } else
29357fa27ce4SDimitry Andric         dbgs() << ReservedCycles[StartIdx + UnitIdx] << "\n";
2936e3b55780SDimitry Andric     }
2937e3b55780SDimitry Andric     StartIdx += NumUnits;
2938e3b55780SDimitry Andric   }
2939e3b55780SDimitry Andric }
2940e3b55780SDimitry Andric 
29415ca98fd9SDimitry Andric // This is useful information to dump after bumpNode.
29425ca98fd9SDimitry Andric // Note that the Queue contents are more useful before pickNodeFromQueue.
dumpScheduledState() const294308bbd35aSDimitry Andric LLVM_DUMP_METHOD void SchedBoundary::dumpScheduledState() const {
29445ca98fd9SDimitry Andric   unsigned ResFactor;
29455ca98fd9SDimitry Andric   unsigned ResCount;
29465ca98fd9SDimitry Andric   if (ZoneCritResIdx) {
29475ca98fd9SDimitry Andric     ResFactor = SchedModel->getResourceFactor(ZoneCritResIdx);
29485ca98fd9SDimitry Andric     ResCount = getResourceCount(ZoneCritResIdx);
294901095a5dSDimitry Andric   } else {
29505ca98fd9SDimitry Andric     ResFactor = SchedModel->getMicroOpFactor();
2951044eb2f6SDimitry Andric     ResCount = RetiredMOps * ResFactor;
29525ca98fd9SDimitry Andric   }
29535ca98fd9SDimitry Andric   unsigned LFactor = SchedModel->getLatencyFactor();
29545ca98fd9SDimitry Andric   dbgs() << Available.getName() << " @" << CurrCycle << "c\n"
29555ca98fd9SDimitry Andric          << "  Retired: " << RetiredMOps;
29565ca98fd9SDimitry Andric   dbgs() << "\n  Executed: " << getExecutedCount() / LFactor << "c";
29575ca98fd9SDimitry Andric   dbgs() << "\n  Critical: " << ResCount / LFactor << "c, "
29585ca98fd9SDimitry Andric          << ResCount / ResFactor << " "
29595ca98fd9SDimitry Andric          << SchedModel->getResourceName(ZoneCritResIdx)
29605ca98fd9SDimitry Andric          << "\n  ExpectedLatency: " << ExpectedLatency << "c\n"
29615ca98fd9SDimitry Andric          << (IsResourceLimited ? "  - Resource" : "  - Latency")
29625ca98fd9SDimitry Andric          << " limited.\n";
2963e3b55780SDimitry Andric   if (MISchedDumpReservedCycles)
2964e3b55780SDimitry Andric     dumpReservedCycles();
29655ca98fd9SDimitry Andric }
29665ca98fd9SDimitry Andric #endif
29675ca98fd9SDimitry Andric 
29685ca98fd9SDimitry Andric //===----------------------------------------------------------------------===//
29695ca98fd9SDimitry Andric // GenericScheduler - Generic implementation of MachineSchedStrategy.
29705ca98fd9SDimitry Andric //===----------------------------------------------------------------------===//
29715ca98fd9SDimitry Andric 
29725ca98fd9SDimitry Andric void GenericSchedulerBase::SchedCandidate::
initResourceDelta(const ScheduleDAGMI * DAG,const TargetSchedModel * SchedModel)29735ca98fd9SDimitry Andric initResourceDelta(const ScheduleDAGMI *DAG,
29745ca98fd9SDimitry Andric                   const TargetSchedModel *SchedModel) {
29755ca98fd9SDimitry Andric   if (!Policy.ReduceResIdx && !Policy.DemandResIdx)
29765ca98fd9SDimitry Andric     return;
29775ca98fd9SDimitry Andric 
29785ca98fd9SDimitry Andric   const MCSchedClassDesc *SC = DAG->getSchedClass(SU);
29795ca98fd9SDimitry Andric   for (TargetSchedModel::ProcResIter
29805ca98fd9SDimitry Andric          PI = SchedModel->getWriteProcResBegin(SC),
29815ca98fd9SDimitry Andric          PE = SchedModel->getWriteProcResEnd(SC); PI != PE; ++PI) {
29825ca98fd9SDimitry Andric     if (PI->ProcResourceIdx == Policy.ReduceResIdx)
2983b1c73532SDimitry Andric       ResDelta.CritResources += PI->ReleaseAtCycle;
29845ca98fd9SDimitry Andric     if (PI->ProcResourceIdx == Policy.DemandResIdx)
2985b1c73532SDimitry Andric       ResDelta.DemandedResources += PI->ReleaseAtCycle;
29865ca98fd9SDimitry Andric   }
29875ca98fd9SDimitry Andric }
29885ca98fd9SDimitry Andric 
2989d8e91e46SDimitry Andric /// Compute remaining latency. We need this both to determine whether the
2990d8e91e46SDimitry Andric /// overall schedule has become latency-limited and whether the instructions
2991d8e91e46SDimitry Andric /// outside this zone are resource or latency limited.
2992d8e91e46SDimitry Andric ///
2993d8e91e46SDimitry Andric /// The "dependent" latency is updated incrementally during scheduling as the
2994d8e91e46SDimitry Andric /// max height/depth of scheduled nodes minus the cycles since it was
2995d8e91e46SDimitry Andric /// scheduled:
2996d8e91e46SDimitry Andric ///   DLat = max (N.depth - (CurrCycle - N.ReadyCycle) for N in Zone
2997d8e91e46SDimitry Andric ///
2998d8e91e46SDimitry Andric /// The "independent" latency is the max ready queue depth:
2999d8e91e46SDimitry Andric ///   ILat = max N.depth for N in Available|Pending
3000d8e91e46SDimitry Andric ///
3001d8e91e46SDimitry Andric /// RemainingLatency is the greater of independent and dependent latency.
3002d8e91e46SDimitry Andric ///
3003d8e91e46SDimitry Andric /// These computations are expensive, especially in DAGs with many edges, so
3004d8e91e46SDimitry Andric /// only do them if necessary.
computeRemLatency(SchedBoundary & CurrZone)3005d8e91e46SDimitry Andric static unsigned computeRemLatency(SchedBoundary &CurrZone) {
3006d8e91e46SDimitry Andric   unsigned RemLatency = CurrZone.getDependentLatency();
3007d8e91e46SDimitry Andric   RemLatency = std::max(RemLatency,
3008d8e91e46SDimitry Andric                         CurrZone.findMaxLatency(CurrZone.Available.elements()));
3009d8e91e46SDimitry Andric   RemLatency = std::max(RemLatency,
3010d8e91e46SDimitry Andric                         CurrZone.findMaxLatency(CurrZone.Pending.elements()));
3011d8e91e46SDimitry Andric   return RemLatency;
3012d8e91e46SDimitry Andric }
3013d8e91e46SDimitry Andric 
3014d8e91e46SDimitry Andric /// Returns true if the current cycle plus remaning latency is greater than
3015d8e91e46SDimitry Andric /// the critical path in the scheduling region.
shouldReduceLatency(const CandPolicy & Policy,SchedBoundary & CurrZone,bool ComputeRemLatency,unsigned & RemLatency) const3016d8e91e46SDimitry Andric bool GenericSchedulerBase::shouldReduceLatency(const CandPolicy &Policy,
3017d8e91e46SDimitry Andric                                                SchedBoundary &CurrZone,
3018d8e91e46SDimitry Andric                                                bool ComputeRemLatency,
3019d8e91e46SDimitry Andric                                                unsigned &RemLatency) const {
3020d8e91e46SDimitry Andric   // The current cycle is already greater than the critical path, so we are
3021d8e91e46SDimitry Andric   // already latency limited and don't need to compute the remaining latency.
3022d8e91e46SDimitry Andric   if (CurrZone.getCurrCycle() > Rem.CriticalPath)
3023d8e91e46SDimitry Andric     return true;
3024d8e91e46SDimitry Andric 
3025d8e91e46SDimitry Andric   // If we haven't scheduled anything yet, then we aren't latency limited.
3026d8e91e46SDimitry Andric   if (CurrZone.getCurrCycle() == 0)
3027d8e91e46SDimitry Andric     return false;
3028d8e91e46SDimitry Andric 
3029d8e91e46SDimitry Andric   if (ComputeRemLatency)
3030d8e91e46SDimitry Andric     RemLatency = computeRemLatency(CurrZone);
3031d8e91e46SDimitry Andric 
3032d8e91e46SDimitry Andric   return RemLatency + CurrZone.getCurrCycle() > Rem.CriticalPath;
3033d8e91e46SDimitry Andric }
3034d8e91e46SDimitry Andric 
30355ca98fd9SDimitry Andric /// Set the CandPolicy given a scheduling zone given the current resources and
30365ca98fd9SDimitry Andric /// latencies inside and outside the zone.
setPolicy(CandPolicy & Policy,bool IsPostRA,SchedBoundary & CurrZone,SchedBoundary * OtherZone)303701095a5dSDimitry Andric void GenericSchedulerBase::setPolicy(CandPolicy &Policy, bool IsPostRA,
30385ca98fd9SDimitry Andric                                      SchedBoundary &CurrZone,
30395ca98fd9SDimitry Andric                                      SchedBoundary *OtherZone) {
30403a0822f0SDimitry Andric   // Apply preemptive heuristics based on the total latency and resources
30415ca98fd9SDimitry Andric   // inside and outside this zone. Potential stalls should be considered before
30425ca98fd9SDimitry Andric   // following this policy.
30435ca98fd9SDimitry Andric 
30445ca98fd9SDimitry Andric   // Compute the critical resource outside the zone.
30455ca98fd9SDimitry Andric   unsigned OtherCritIdx = 0;
30465ca98fd9SDimitry Andric   unsigned OtherCount =
30475ca98fd9SDimitry Andric     OtherZone ? OtherZone->getOtherResourceCount(OtherCritIdx) : 0;
30485ca98fd9SDimitry Andric 
30495ca98fd9SDimitry Andric   bool OtherResLimited = false;
3050d8e91e46SDimitry Andric   unsigned RemLatency = 0;
3051d8e91e46SDimitry Andric   bool RemLatencyComputed = false;
3052d8e91e46SDimitry Andric   if (SchedModel->hasInstrSchedModel() && OtherCount != 0) {
3053d8e91e46SDimitry Andric     RemLatency = computeRemLatency(CurrZone);
3054d8e91e46SDimitry Andric     RemLatencyComputed = true;
3055044eb2f6SDimitry Andric     OtherResLimited = checkResourceLimit(SchedModel->getLatencyFactor(),
3056e6d15924SDimitry Andric                                          OtherCount, RemLatency, false);
3057d8e91e46SDimitry Andric   }
3058044eb2f6SDimitry Andric 
30595ca98fd9SDimitry Andric   // Schedule aggressively for latency in PostRA mode. We don't check for
30605ca98fd9SDimitry Andric   // acyclic latency during PostRA, and highly out-of-order processors will
30615ca98fd9SDimitry Andric   // skip PostRA scheduling.
3062d8e91e46SDimitry Andric   if (!OtherResLimited &&
3063d8e91e46SDimitry Andric       (IsPostRA || shouldReduceLatency(Policy, CurrZone, !RemLatencyComputed,
3064d8e91e46SDimitry Andric                                        RemLatency))) {
30655ca98fd9SDimitry Andric     Policy.ReduceLatency |= true;
3066eb11fae6SDimitry Andric     LLVM_DEBUG(dbgs() << "  " << CurrZone.Available.getName()
30675ca98fd9SDimitry Andric                       << " RemainingLatency " << RemLatency << " + "
30685ca98fd9SDimitry Andric                       << CurrZone.getCurrCycle() << "c > CritPath "
30695ca98fd9SDimitry Andric                       << Rem.CriticalPath << "\n");
30705ca98fd9SDimitry Andric   }
30715ca98fd9SDimitry Andric   // If the same resource is limiting inside and outside the zone, do nothing.
30725ca98fd9SDimitry Andric   if (CurrZone.getZoneCritResIdx() == OtherCritIdx)
30735ca98fd9SDimitry Andric     return;
30745ca98fd9SDimitry Andric 
3075eb11fae6SDimitry Andric   LLVM_DEBUG(if (CurrZone.isResourceLimited()) {
30765ca98fd9SDimitry Andric     dbgs() << "  " << CurrZone.Available.getName() << " ResourceLimited: "
3077eb11fae6SDimitry Andric            << SchedModel->getResourceName(CurrZone.getZoneCritResIdx()) << "\n";
3078eb11fae6SDimitry Andric   } if (OtherResLimited) dbgs()
3079eb11fae6SDimitry Andric                  << "  RemainingLimit: "
30805ca98fd9SDimitry Andric                  << SchedModel->getResourceName(OtherCritIdx) << "\n";
3081eb11fae6SDimitry Andric              if (!CurrZone.isResourceLimited() && !OtherResLimited) dbgs()
3082eb11fae6SDimitry Andric              << "  Latency limited both directions.\n");
30835ca98fd9SDimitry Andric 
30845ca98fd9SDimitry Andric   if (CurrZone.isResourceLimited() && !Policy.ReduceResIdx)
30855ca98fd9SDimitry Andric     Policy.ReduceResIdx = CurrZone.getZoneCritResIdx();
30865ca98fd9SDimitry Andric 
30875ca98fd9SDimitry Andric   if (OtherResLimited)
30885ca98fd9SDimitry Andric     Policy.DemandResIdx = OtherCritIdx;
30895ca98fd9SDimitry Andric }
30905ca98fd9SDimitry Andric 
30915ca98fd9SDimitry Andric #ifndef NDEBUG
getReasonStr(GenericSchedulerBase::CandReason Reason)30925ca98fd9SDimitry Andric const char *GenericSchedulerBase::getReasonStr(
30935ca98fd9SDimitry Andric   GenericSchedulerBase::CandReason Reason) {
30945ca98fd9SDimitry Andric   switch (Reason) {
30955ca98fd9SDimitry Andric   case NoCand:         return "NOCAND    ";
309601095a5dSDimitry Andric   case Only1:          return "ONLY1     ";
3097d8e91e46SDimitry Andric   case PhysReg:        return "PHYS-REG  ";
30985ca98fd9SDimitry Andric   case RegExcess:      return "REG-EXCESS";
30995ca98fd9SDimitry Andric   case RegCritical:    return "REG-CRIT  ";
31005ca98fd9SDimitry Andric   case Stall:          return "STALL     ";
31015ca98fd9SDimitry Andric   case Cluster:        return "CLUSTER   ";
31025ca98fd9SDimitry Andric   case Weak:           return "WEAK      ";
31035ca98fd9SDimitry Andric   case RegMax:         return "REG-MAX   ";
31045ca98fd9SDimitry Andric   case ResourceReduce: return "RES-REDUCE";
31055ca98fd9SDimitry Andric   case ResourceDemand: return "RES-DEMAND";
31065ca98fd9SDimitry Andric   case TopDepthReduce: return "TOP-DEPTH ";
31075ca98fd9SDimitry Andric   case TopPathReduce:  return "TOP-PATH  ";
31085ca98fd9SDimitry Andric   case BotHeightReduce:return "BOT-HEIGHT";
31095ca98fd9SDimitry Andric   case BotPathReduce:  return "BOT-PATH  ";
31105ca98fd9SDimitry Andric   case NextDefUse:     return "DEF-USE   ";
31115ca98fd9SDimitry Andric   case NodeOrder:      return "ORDER     ";
31125ca98fd9SDimitry Andric   };
31135ca98fd9SDimitry Andric   llvm_unreachable("Unknown reason!");
31145ca98fd9SDimitry Andric }
31155ca98fd9SDimitry Andric 
traceCandidate(const SchedCandidate & Cand)31165ca98fd9SDimitry Andric void GenericSchedulerBase::traceCandidate(const SchedCandidate &Cand) {
31175ca98fd9SDimitry Andric   PressureChange P;
31185ca98fd9SDimitry Andric   unsigned ResIdx = 0;
31195ca98fd9SDimitry Andric   unsigned Latency = 0;
31205ca98fd9SDimitry Andric   switch (Cand.Reason) {
31215ca98fd9SDimitry Andric   default:
31225ca98fd9SDimitry Andric     break;
31235ca98fd9SDimitry Andric   case RegExcess:
31245ca98fd9SDimitry Andric     P = Cand.RPDelta.Excess;
31255ca98fd9SDimitry Andric     break;
31265ca98fd9SDimitry Andric   case RegCritical:
31275ca98fd9SDimitry Andric     P = Cand.RPDelta.CriticalMax;
31285ca98fd9SDimitry Andric     break;
31295ca98fd9SDimitry Andric   case RegMax:
31305ca98fd9SDimitry Andric     P = Cand.RPDelta.CurrentMax;
31315ca98fd9SDimitry Andric     break;
31325ca98fd9SDimitry Andric   case ResourceReduce:
31335ca98fd9SDimitry Andric     ResIdx = Cand.Policy.ReduceResIdx;
31345ca98fd9SDimitry Andric     break;
31355ca98fd9SDimitry Andric   case ResourceDemand:
31365ca98fd9SDimitry Andric     ResIdx = Cand.Policy.DemandResIdx;
31375ca98fd9SDimitry Andric     break;
31385ca98fd9SDimitry Andric   case TopDepthReduce:
31395ca98fd9SDimitry Andric     Latency = Cand.SU->getDepth();
31405ca98fd9SDimitry Andric     break;
31415ca98fd9SDimitry Andric   case TopPathReduce:
31425ca98fd9SDimitry Andric     Latency = Cand.SU->getHeight();
31435ca98fd9SDimitry Andric     break;
31445ca98fd9SDimitry Andric   case BotHeightReduce:
31455ca98fd9SDimitry Andric     Latency = Cand.SU->getHeight();
31465ca98fd9SDimitry Andric     break;
31475ca98fd9SDimitry Andric   case BotPathReduce:
31485ca98fd9SDimitry Andric     Latency = Cand.SU->getDepth();
31495ca98fd9SDimitry Andric     break;
31505ca98fd9SDimitry Andric   }
3151dd58ef01SDimitry Andric   dbgs() << "  Cand SU(" << Cand.SU->NodeNum << ") " << getReasonStr(Cand.Reason);
31525ca98fd9SDimitry Andric   if (P.isValid())
31535ca98fd9SDimitry Andric     dbgs() << " " << TRI->getRegPressureSetName(P.getPSet())
31545ca98fd9SDimitry Andric            << ":" << P.getUnitInc() << " ";
31555ca98fd9SDimitry Andric   else
31565ca98fd9SDimitry Andric     dbgs() << "      ";
31575ca98fd9SDimitry Andric   if (ResIdx)
31585ca98fd9SDimitry Andric     dbgs() << " " << SchedModel->getProcResource(ResIdx)->Name << " ";
31595ca98fd9SDimitry Andric   else
31605ca98fd9SDimitry Andric     dbgs() << "         ";
31615ca98fd9SDimitry Andric   if (Latency)
31625ca98fd9SDimitry Andric     dbgs() << " " << Latency << " cycles ";
31635ca98fd9SDimitry Andric   else
31645ca98fd9SDimitry Andric     dbgs() << "          ";
31655ca98fd9SDimitry Andric   dbgs() << '\n';
31665ca98fd9SDimitry Andric }
31675ca98fd9SDimitry Andric #endif
31685ca98fd9SDimitry Andric 
3169eb11fae6SDimitry Andric namespace llvm {
31705ca98fd9SDimitry Andric /// Return true if this heuristic determines order.
3171344a3780SDimitry Andric /// TODO: Consider refactor return type of these functions as integer or enum,
3172344a3780SDimitry Andric /// as we may need to differentiate whether TryCand is better than Cand.
tryLess(int TryVal,int CandVal,GenericSchedulerBase::SchedCandidate & TryCand,GenericSchedulerBase::SchedCandidate & Cand,GenericSchedulerBase::CandReason Reason)3173eb11fae6SDimitry Andric bool tryLess(int TryVal, int CandVal,
31745ca98fd9SDimitry Andric              GenericSchedulerBase::SchedCandidate &TryCand,
31755ca98fd9SDimitry Andric              GenericSchedulerBase::SchedCandidate &Cand,
31765ca98fd9SDimitry Andric              GenericSchedulerBase::CandReason Reason) {
31775ca98fd9SDimitry Andric   if (TryVal < CandVal) {
31785ca98fd9SDimitry Andric     TryCand.Reason = Reason;
31795ca98fd9SDimitry Andric     return true;
31805ca98fd9SDimitry Andric   }
31815ca98fd9SDimitry Andric   if (TryVal > CandVal) {
31825ca98fd9SDimitry Andric     if (Cand.Reason > Reason)
31835ca98fd9SDimitry Andric       Cand.Reason = Reason;
31845ca98fd9SDimitry Andric     return true;
31855ca98fd9SDimitry Andric   }
31865ca98fd9SDimitry Andric   return false;
31875ca98fd9SDimitry Andric }
31885ca98fd9SDimitry Andric 
tryGreater(int TryVal,int CandVal,GenericSchedulerBase::SchedCandidate & TryCand,GenericSchedulerBase::SchedCandidate & Cand,GenericSchedulerBase::CandReason Reason)3189eb11fae6SDimitry Andric bool tryGreater(int TryVal, int CandVal,
31905ca98fd9SDimitry Andric                 GenericSchedulerBase::SchedCandidate &TryCand,
31915ca98fd9SDimitry Andric                 GenericSchedulerBase::SchedCandidate &Cand,
31925ca98fd9SDimitry Andric                 GenericSchedulerBase::CandReason Reason) {
31935ca98fd9SDimitry Andric   if (TryVal > CandVal) {
31945ca98fd9SDimitry Andric     TryCand.Reason = Reason;
31955ca98fd9SDimitry Andric     return true;
31965ca98fd9SDimitry Andric   }
31975ca98fd9SDimitry Andric   if (TryVal < CandVal) {
31985ca98fd9SDimitry Andric     if (Cand.Reason > Reason)
31995ca98fd9SDimitry Andric       Cand.Reason = Reason;
32005ca98fd9SDimitry Andric     return true;
32015ca98fd9SDimitry Andric   }
32025ca98fd9SDimitry Andric   return false;
32035ca98fd9SDimitry Andric }
32045ca98fd9SDimitry Andric 
tryLatency(GenericSchedulerBase::SchedCandidate & TryCand,GenericSchedulerBase::SchedCandidate & Cand,SchedBoundary & Zone)3205eb11fae6SDimitry Andric bool tryLatency(GenericSchedulerBase::SchedCandidate &TryCand,
32065ca98fd9SDimitry Andric                 GenericSchedulerBase::SchedCandidate &Cand,
32075ca98fd9SDimitry Andric                 SchedBoundary &Zone) {
32085ca98fd9SDimitry Andric   if (Zone.isTop()) {
3209b60736ecSDimitry Andric     // Prefer the candidate with the lesser depth, but only if one of them has
3210b60736ecSDimitry Andric     // depth greater than the total latency scheduled so far, otherwise either
3211b60736ecSDimitry Andric     // of them could be scheduled now with no stall.
3212b60736ecSDimitry Andric     if (std::max(TryCand.SU->getDepth(), Cand.SU->getDepth()) >
3213b60736ecSDimitry Andric         Zone.getScheduledLatency()) {
32145ca98fd9SDimitry Andric       if (tryLess(TryCand.SU->getDepth(), Cand.SU->getDepth(),
32155ca98fd9SDimitry Andric                   TryCand, Cand, GenericSchedulerBase::TopDepthReduce))
32165ca98fd9SDimitry Andric         return true;
32175ca98fd9SDimitry Andric     }
32185ca98fd9SDimitry Andric     if (tryGreater(TryCand.SU->getHeight(), Cand.SU->getHeight(),
32195ca98fd9SDimitry Andric                    TryCand, Cand, GenericSchedulerBase::TopPathReduce))
32205ca98fd9SDimitry Andric       return true;
322101095a5dSDimitry Andric   } else {
3222b60736ecSDimitry Andric     // Prefer the candidate with the lesser height, but only if one of them has
3223b60736ecSDimitry Andric     // height greater than the total latency scheduled so far, otherwise either
3224b60736ecSDimitry Andric     // of them could be scheduled now with no stall.
3225b60736ecSDimitry Andric     if (std::max(TryCand.SU->getHeight(), Cand.SU->getHeight()) >
3226b60736ecSDimitry Andric         Zone.getScheduledLatency()) {
32275ca98fd9SDimitry Andric       if (tryLess(TryCand.SU->getHeight(), Cand.SU->getHeight(),
32285ca98fd9SDimitry Andric                   TryCand, Cand, GenericSchedulerBase::BotHeightReduce))
32295ca98fd9SDimitry Andric         return true;
32305ca98fd9SDimitry Andric     }
32315ca98fd9SDimitry Andric     if (tryGreater(TryCand.SU->getDepth(), Cand.SU->getDepth(),
32325ca98fd9SDimitry Andric                    TryCand, Cand, GenericSchedulerBase::BotPathReduce))
32335ca98fd9SDimitry Andric       return true;
32345ca98fd9SDimitry Andric   }
32355ca98fd9SDimitry Andric   return false;
32365ca98fd9SDimitry Andric }
3237eb11fae6SDimitry Andric } // end namespace llvm
32385ca98fd9SDimitry Andric 
tracePick(GenericSchedulerBase::CandReason Reason,bool IsTop)323901095a5dSDimitry Andric static void tracePick(GenericSchedulerBase::CandReason Reason, bool IsTop) {
3240eb11fae6SDimitry Andric   LLVM_DEBUG(dbgs() << "Pick " << (IsTop ? "Top " : "Bot ")
324101095a5dSDimitry Andric                     << GenericSchedulerBase::getReasonStr(Reason) << '\n');
324201095a5dSDimitry Andric }
324301095a5dSDimitry Andric 
tracePick(const GenericSchedulerBase::SchedCandidate & Cand)324401095a5dSDimitry Andric static void tracePick(const GenericSchedulerBase::SchedCandidate &Cand) {
324501095a5dSDimitry Andric   tracePick(Cand.Reason, Cand.AtTop);
32465ca98fd9SDimitry Andric }
32475ca98fd9SDimitry Andric 
initialize(ScheduleDAGMI * dag)32485ca98fd9SDimitry Andric void GenericScheduler::initialize(ScheduleDAGMI *dag) {
32495ca98fd9SDimitry Andric   assert(dag->hasVRegLiveness() &&
32505ca98fd9SDimitry Andric          "(PreRA)GenericScheduler needs vreg liveness");
32515ca98fd9SDimitry Andric   DAG = static_cast<ScheduleDAGMILive*>(dag);
32525ca98fd9SDimitry Andric   SchedModel = DAG->getSchedModel();
32535ca98fd9SDimitry Andric   TRI = DAG->TRI;
32545ca98fd9SDimitry Andric 
3255cfca06d7SDimitry Andric   if (RegionPolicy.ComputeDFSResult)
3256cfca06d7SDimitry Andric     DAG->computeDFSResult();
3257cfca06d7SDimitry Andric 
32585ca98fd9SDimitry Andric   Rem.init(DAG, SchedModel);
32595ca98fd9SDimitry Andric   Top.init(DAG, SchedModel, &Rem);
32605ca98fd9SDimitry Andric   Bot.init(DAG, SchedModel, &Rem);
32615ca98fd9SDimitry Andric 
32625ca98fd9SDimitry Andric   // Initialize resource counts.
32635ca98fd9SDimitry Andric 
32645ca98fd9SDimitry Andric   // Initialize the HazardRecognizers. If itineraries don't exist, are empty, or
32655ca98fd9SDimitry Andric   // are disabled, then these HazardRecs will be disabled.
32665ca98fd9SDimitry Andric   const InstrItineraryData *Itin = SchedModel->getInstrItineraries();
32675ca98fd9SDimitry Andric   if (!Top.HazardRec) {
3268ac9a064cSDimitry Andric     Top.HazardRec = DAG->TII->CreateTargetMIHazardRecognizer(Itin, DAG);
32695ca98fd9SDimitry Andric   }
32705ca98fd9SDimitry Andric   if (!Bot.HazardRec) {
3271ac9a064cSDimitry Andric     Bot.HazardRec = DAG->TII->CreateTargetMIHazardRecognizer(Itin, DAG);
32725ca98fd9SDimitry Andric   }
327301095a5dSDimitry Andric   TopCand.SU = nullptr;
327401095a5dSDimitry Andric   BotCand.SU = nullptr;
3275522600a2SDimitry Andric }
3276522600a2SDimitry Andric 
3277f8af5cf6SDimitry Andric /// Initialize the per-region scheduling policy.
initPolicy(MachineBasicBlock::iterator Begin,MachineBasicBlock::iterator End,unsigned NumRegionInstrs)3278f8af5cf6SDimitry Andric void GenericScheduler::initPolicy(MachineBasicBlock::iterator Begin,
3279f8af5cf6SDimitry Andric                                   MachineBasicBlock::iterator End,
3280f8af5cf6SDimitry Andric                                   unsigned NumRegionInstrs) {
3281044eb2f6SDimitry Andric   const MachineFunction &MF = *Begin->getMF();
328267c32a98SDimitry Andric   const TargetLowering *TLI = MF.getSubtarget().getTargetLowering();
3283f8af5cf6SDimitry Andric 
3284f8af5cf6SDimitry Andric   // Avoid setting up the register pressure tracker for small regions to save
3285f8af5cf6SDimitry Andric   // compile time. As a rough heuristic, only track pressure when the number of
3286ac9a064cSDimitry Andric   // schedulable instructions exceeds half the allocatable integer register file
3287ac9a064cSDimitry Andric   // that is the largest legal integer regiser type.
32885ca98fd9SDimitry Andric   RegionPolicy.ShouldTrackPressure = true;
3289ac9a064cSDimitry Andric   for (unsigned VT = MVT::i64; VT > (unsigned)MVT::i1; --VT) {
32905ca98fd9SDimitry Andric     MVT::SimpleValueType LegalIntVT = (MVT::SimpleValueType)VT;
32915ca98fd9SDimitry Andric     if (TLI->isTypeLegal(LegalIntVT)) {
3292f8af5cf6SDimitry Andric       unsigned NIntRegs = Context->RegClassInfo->getNumAllocatableRegs(
32935ca98fd9SDimitry Andric         TLI->getRegClassFor(LegalIntVT));
3294f8af5cf6SDimitry Andric       RegionPolicy.ShouldTrackPressure = NumRegionInstrs > (NIntRegs / 2);
3295ac9a064cSDimitry Andric       break;
32965ca98fd9SDimitry Andric     }
32975ca98fd9SDimitry Andric   }
3298f8af5cf6SDimitry Andric 
3299f8af5cf6SDimitry Andric   // For generic targets, we default to bottom-up, because it's simpler and more
3300f8af5cf6SDimitry Andric   // compile-time optimizations have been implemented in that direction.
3301f8af5cf6SDimitry Andric   RegionPolicy.OnlyBottomUp = true;
3302f8af5cf6SDimitry Andric 
3303f8af5cf6SDimitry Andric   // Allow the subtarget to override default policy.
330401095a5dSDimitry Andric   MF.getSubtarget().overrideSchedPolicy(RegionPolicy, NumRegionInstrs);
3305f8af5cf6SDimitry Andric 
3306f8af5cf6SDimitry Andric   // After subtarget overrides, apply command line options.
3307e6d15924SDimitry Andric   if (!EnableRegPressure) {
3308f8af5cf6SDimitry Andric     RegionPolicy.ShouldTrackPressure = false;
3309e6d15924SDimitry Andric     RegionPolicy.ShouldTrackLaneMasks = false;
3310e6d15924SDimitry Andric   }
3311f8af5cf6SDimitry Andric 
3312f8af5cf6SDimitry Andric   // Check -misched-topdown/bottomup can force or unforce scheduling direction.
3313f8af5cf6SDimitry Andric   // e.g. -misched-bottomup=false allows scheduling in both directions.
3314f8af5cf6SDimitry Andric   assert((!ForceTopDown || !ForceBottomUp) &&
3315f8af5cf6SDimitry Andric          "-misched-topdown incompatible with -misched-bottomup");
3316f8af5cf6SDimitry Andric   if (ForceBottomUp.getNumOccurrences() > 0) {
3317f8af5cf6SDimitry Andric     RegionPolicy.OnlyBottomUp = ForceBottomUp;
3318f8af5cf6SDimitry Andric     if (RegionPolicy.OnlyBottomUp)
3319f8af5cf6SDimitry Andric       RegionPolicy.OnlyTopDown = false;
3320f8af5cf6SDimitry Andric   }
3321f8af5cf6SDimitry Andric   if (ForceTopDown.getNumOccurrences() > 0) {
3322f8af5cf6SDimitry Andric     RegionPolicy.OnlyTopDown = ForceTopDown;
3323f8af5cf6SDimitry Andric     if (RegionPolicy.OnlyTopDown)
3324f8af5cf6SDimitry Andric       RegionPolicy.OnlyBottomUp = false;
3325f8af5cf6SDimitry Andric   }
3326f8af5cf6SDimitry Andric }
3327f8af5cf6SDimitry Andric 
dumpPolicy() const332808bbd35aSDimitry Andric void GenericScheduler::dumpPolicy() const {
332971d5a254SDimitry Andric   // Cannot completely remove virtual function even in release mode.
333071d5a254SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
3331dd58ef01SDimitry Andric   dbgs() << "GenericScheduler RegionPolicy: "
3332dd58ef01SDimitry Andric          << " ShouldTrackPressure=" << RegionPolicy.ShouldTrackPressure
3333dd58ef01SDimitry Andric          << " OnlyTopDown=" << RegionPolicy.OnlyTopDown
3334dd58ef01SDimitry Andric          << " OnlyBottomUp=" << RegionPolicy.OnlyBottomUp
3335dd58ef01SDimitry Andric          << "\n";
333671d5a254SDimitry Andric #endif
3337dd58ef01SDimitry Andric }
3338dd58ef01SDimitry Andric 
3339f8af5cf6SDimitry Andric /// Set IsAcyclicLatencyLimited if the acyclic path is longer than the cyclic
3340f8af5cf6SDimitry Andric /// critical path by more cycles than it takes to drain the instruction buffer.
3341f8af5cf6SDimitry Andric /// We estimate an upper bounds on in-flight instructions as:
3342f8af5cf6SDimitry Andric ///
3343f8af5cf6SDimitry Andric /// CyclesPerIteration = max( CyclicPath, Loop-Resource-Height )
3344f8af5cf6SDimitry Andric /// InFlightIterations = AcyclicPath / CyclesPerIteration
3345f8af5cf6SDimitry Andric /// InFlightResources = InFlightIterations * LoopResources
3346f8af5cf6SDimitry Andric ///
3347f8af5cf6SDimitry Andric /// TODO: Check execution resources in addition to IssueCount.
checkAcyclicLatency()3348f8af5cf6SDimitry Andric void GenericScheduler::checkAcyclicLatency() {
3349f8af5cf6SDimitry Andric   if (Rem.CyclicCritPath == 0 || Rem.CyclicCritPath >= Rem.CriticalPath)
3350f8af5cf6SDimitry Andric     return;
3351f8af5cf6SDimitry Andric 
3352f8af5cf6SDimitry Andric   // Scaled number of cycles per loop iteration.
3353f8af5cf6SDimitry Andric   unsigned IterCount =
3354f8af5cf6SDimitry Andric     std::max(Rem.CyclicCritPath * SchedModel->getLatencyFactor(),
3355f8af5cf6SDimitry Andric              Rem.RemIssueCount);
3356f8af5cf6SDimitry Andric   // Scaled acyclic critical path.
3357f8af5cf6SDimitry Andric   unsigned AcyclicCount = Rem.CriticalPath * SchedModel->getLatencyFactor();
3358f8af5cf6SDimitry Andric   // InFlightCount = (AcyclicPath / IterCycles) * InstrPerLoop
3359f8af5cf6SDimitry Andric   unsigned InFlightCount =
3360f8af5cf6SDimitry Andric     (AcyclicCount * Rem.RemIssueCount + IterCount-1) / IterCount;
3361f8af5cf6SDimitry Andric   unsigned BufferLimit =
3362f8af5cf6SDimitry Andric     SchedModel->getMicroOpBufferSize() * SchedModel->getMicroOpFactor();
3363f8af5cf6SDimitry Andric 
3364f8af5cf6SDimitry Andric   Rem.IsAcyclicLatencyLimited = InFlightCount > BufferLimit;
3365f8af5cf6SDimitry Andric 
3366eb11fae6SDimitry Andric   LLVM_DEBUG(
3367eb11fae6SDimitry Andric       dbgs() << "IssueCycles="
3368f8af5cf6SDimitry Andric              << Rem.RemIssueCount / SchedModel->getLatencyFactor() << "c "
3369f8af5cf6SDimitry Andric              << "IterCycles=" << IterCount / SchedModel->getLatencyFactor()
3370f8af5cf6SDimitry Andric              << "c NumIters=" << (AcyclicCount + IterCount - 1) / IterCount
3371f8af5cf6SDimitry Andric              << " InFlight=" << InFlightCount / SchedModel->getMicroOpFactor()
3372f8af5cf6SDimitry Andric              << "m BufferLim=" << SchedModel->getMicroOpBufferSize() << "m\n";
3373eb11fae6SDimitry Andric       if (Rem.IsAcyclicLatencyLimited) dbgs() << "  ACYCLIC LATENCY LIMIT\n");
3374f8af5cf6SDimitry Andric }
3375f8af5cf6SDimitry Andric 
registerRoots()3376f8af5cf6SDimitry Andric void GenericScheduler::registerRoots() {
3377522600a2SDimitry Andric   Rem.CriticalPath = DAG->ExitSU.getDepth();
3378f8af5cf6SDimitry Andric 
3379522600a2SDimitry Andric   // Some roots may not feed into ExitSU. Check all of them in case.
338008bbd35aSDimitry Andric   for (const SUnit *SU : Bot.Available) {
338108bbd35aSDimitry Andric     if (SU->getDepth() > Rem.CriticalPath)
338208bbd35aSDimitry Andric       Rem.CriticalPath = SU->getDepth();
3383522600a2SDimitry Andric   }
3384eb11fae6SDimitry Andric   LLVM_DEBUG(dbgs() << "Critical Path(GS-RR ): " << Rem.CriticalPath << '\n');
338567c32a98SDimitry Andric   if (DumpCriticalPathLength) {
338667c32a98SDimitry Andric     errs() << "Critical Path(GS-RR ): " << Rem.CriticalPath << " \n";
338767c32a98SDimitry Andric   }
3388f8af5cf6SDimitry Andric 
338971d5a254SDimitry Andric   if (EnableCyclicPath && SchedModel->getMicroOpBufferSize() > 0) {
3390f8af5cf6SDimitry Andric     Rem.CyclicCritPath = DAG->computeCyclicCriticalPath();
3391f8af5cf6SDimitry Andric     checkAcyclicLatency();
3392f8af5cf6SDimitry Andric   }
3393522600a2SDimitry Andric }
3394522600a2SDimitry Andric 
3395eb11fae6SDimitry Andric namespace llvm {
tryPressure(const PressureChange & TryP,const PressureChange & CandP,GenericSchedulerBase::SchedCandidate & TryCand,GenericSchedulerBase::SchedCandidate & Cand,GenericSchedulerBase::CandReason Reason,const TargetRegisterInfo * TRI,const MachineFunction & MF)3396eb11fae6SDimitry Andric bool tryPressure(const PressureChange &TryP,
3397f8af5cf6SDimitry Andric                  const PressureChange &CandP,
33985ca98fd9SDimitry Andric                  GenericSchedulerBase::SchedCandidate &TryCand,
33995ca98fd9SDimitry Andric                  GenericSchedulerBase::SchedCandidate &Cand,
3400dd58ef01SDimitry Andric                  GenericSchedulerBase::CandReason Reason,
3401dd58ef01SDimitry Andric                  const TargetRegisterInfo *TRI,
3402dd58ef01SDimitry Andric                  const MachineFunction &MF) {
3403f8af5cf6SDimitry Andric   // If one candidate decreases and the other increases, go with it.
3404f8af5cf6SDimitry Andric   // Invalid candidates have UnitInc==0.
340567c32a98SDimitry Andric   if (tryGreater(TryP.getUnitInc() < 0, CandP.getUnitInc() < 0, TryCand, Cand,
3406f8af5cf6SDimitry Andric                  Reason)) {
3407f8af5cf6SDimitry Andric     return true;
3408f8af5cf6SDimitry Andric   }
340901095a5dSDimitry Andric   // Do not compare the magnitude of pressure changes between top and bottom
341001095a5dSDimitry Andric   // boundary.
341101095a5dSDimitry Andric   if (Cand.AtTop != TryCand.AtTop)
341201095a5dSDimitry Andric     return false;
341301095a5dSDimitry Andric 
341401095a5dSDimitry Andric   // If both candidates affect the same set in the same boundary, go with the
341501095a5dSDimitry Andric   // smallest increase.
341601095a5dSDimitry Andric   unsigned TryPSet = TryP.getPSetOrMax();
341701095a5dSDimitry Andric   unsigned CandPSet = CandP.getPSetOrMax();
341801095a5dSDimitry Andric   if (TryPSet == CandPSet) {
341901095a5dSDimitry Andric     return tryLess(TryP.getUnitInc(), CandP.getUnitInc(), TryCand, Cand,
342001095a5dSDimitry Andric                    Reason);
342101095a5dSDimitry Andric   }
3422dd58ef01SDimitry Andric 
3423dd58ef01SDimitry Andric   int TryRank = TryP.isValid() ? TRI->getRegPressureSetScore(MF, TryPSet) :
3424dd58ef01SDimitry Andric                                  std::numeric_limits<int>::max();
3425dd58ef01SDimitry Andric 
3426dd58ef01SDimitry Andric   int CandRank = CandP.isValid() ? TRI->getRegPressureSetScore(MF, CandPSet) :
3427dd58ef01SDimitry Andric                                    std::numeric_limits<int>::max();
3428dd58ef01SDimitry Andric 
3429f8af5cf6SDimitry Andric   // If the candidates are decreasing pressure, reverse priority.
3430f8af5cf6SDimitry Andric   if (TryP.getUnitInc() < 0)
3431f8af5cf6SDimitry Andric     std::swap(TryRank, CandRank);
3432f8af5cf6SDimitry Andric   return tryGreater(TryRank, CandRank, TryCand, Cand, Reason);
3433f8af5cf6SDimitry Andric }
3434f8af5cf6SDimitry Andric 
getWeakLeft(const SUnit * SU,bool isTop)3435eb11fae6SDimitry Andric unsigned getWeakLeft(const SUnit *SU, bool isTop) {
34364a16efa3SDimitry Andric   return (isTop) ? SU->WeakPredsLeft : SU->WeakSuccsLeft;
34374a16efa3SDimitry Andric }
34384a16efa3SDimitry Andric 
343959d6cff9SDimitry Andric /// Minimize physical register live ranges. Regalloc wants them adjacent to
344059d6cff9SDimitry Andric /// their physreg def/use.
344159d6cff9SDimitry Andric ///
344259d6cff9SDimitry Andric /// FIXME: This is an unnecessary check on the critical path. Most are root/leaf
344359d6cff9SDimitry Andric /// copies which can be prescheduled. The rest (e.g. x86 MUL) could be bundled
344459d6cff9SDimitry Andric /// with the operation that produces or consumes the physreg. We'll do this when
344559d6cff9SDimitry Andric /// regalloc has support for parallel copies.
biasPhysReg(const SUnit * SU,bool isTop)3446d8e91e46SDimitry Andric int biasPhysReg(const SUnit *SU, bool isTop) {
344759d6cff9SDimitry Andric   const MachineInstr *MI = SU->getInstr();
344859d6cff9SDimitry Andric 
3449d8e91e46SDimitry Andric   if (MI->isCopy()) {
345059d6cff9SDimitry Andric     unsigned ScheduledOper = isTop ? 1 : 0;
345159d6cff9SDimitry Andric     unsigned UnscheduledOper = isTop ? 0 : 1;
345259d6cff9SDimitry Andric     // If we have already scheduled the physreg produce/consumer, immediately
345359d6cff9SDimitry Andric     // schedule the copy.
3454e3b55780SDimitry Andric     if (MI->getOperand(ScheduledOper).getReg().isPhysical())
345559d6cff9SDimitry Andric       return 1;
345659d6cff9SDimitry Andric     // If the physreg is at the boundary, defer it. Otherwise schedule it
345759d6cff9SDimitry Andric     // immediately to free the dependent. We can hoist the copy later.
345859d6cff9SDimitry Andric     bool AtBoundary = isTop ? !SU->NumSuccsLeft : !SU->NumPredsLeft;
3459e3b55780SDimitry Andric     if (MI->getOperand(UnscheduledOper).getReg().isPhysical())
346059d6cff9SDimitry Andric       return AtBoundary ? -1 : 1;
3461d8e91e46SDimitry Andric   }
3462d8e91e46SDimitry Andric 
3463d8e91e46SDimitry Andric   if (MI->isMoveImmediate()) {
3464d8e91e46SDimitry Andric     // If we have a move immediate and all successors have been assigned, bias
3465d8e91e46SDimitry Andric     // towards scheduling this later. Make sure all register defs are to
3466d8e91e46SDimitry Andric     // physical registers.
3467d8e91e46SDimitry Andric     bool DoBias = true;
3468d8e91e46SDimitry Andric     for (const MachineOperand &Op : MI->defs()) {
3469e3b55780SDimitry Andric       if (Op.isReg() && !Op.getReg().isPhysical()) {
3470d8e91e46SDimitry Andric         DoBias = false;
3471d8e91e46SDimitry Andric         break;
3472d8e91e46SDimitry Andric       }
3473d8e91e46SDimitry Andric     }
3474d8e91e46SDimitry Andric 
3475d8e91e46SDimitry Andric     if (DoBias)
3476d8e91e46SDimitry Andric       return isTop ? -1 : 1;
3477d8e91e46SDimitry Andric   }
3478d8e91e46SDimitry Andric 
347959d6cff9SDimitry Andric   return 0;
348059d6cff9SDimitry Andric }
3481eb11fae6SDimitry Andric } // end namespace llvm
348259d6cff9SDimitry Andric 
initCandidate(SchedCandidate & Cand,SUnit * SU,bool AtTop,const RegPressureTracker & RPTracker,RegPressureTracker & TempTracker)348301095a5dSDimitry Andric void GenericScheduler::initCandidate(SchedCandidate &Cand, SUnit *SU,
348401095a5dSDimitry Andric                                      bool AtTop,
348501095a5dSDimitry Andric                                      const RegPressureTracker &RPTracker,
348601095a5dSDimitry Andric                                      RegPressureTracker &TempTracker) {
348701095a5dSDimitry Andric   Cand.SU = SU;
348801095a5dSDimitry Andric   Cand.AtTop = AtTop;
348901095a5dSDimitry Andric   if (DAG->isTrackingPressure()) {
349001095a5dSDimitry Andric     if (AtTop) {
349101095a5dSDimitry Andric       TempTracker.getMaxDownwardPressureDelta(
349201095a5dSDimitry Andric         Cand.SU->getInstr(),
349301095a5dSDimitry Andric         Cand.RPDelta,
349401095a5dSDimitry Andric         DAG->getRegionCriticalPSets(),
349501095a5dSDimitry Andric         DAG->getRegPressure().MaxSetPressure);
349601095a5dSDimitry Andric     } else {
349701095a5dSDimitry Andric       if (VerifyScheduling) {
349801095a5dSDimitry Andric         TempTracker.getMaxUpwardPressureDelta(
349901095a5dSDimitry Andric           Cand.SU->getInstr(),
350001095a5dSDimitry Andric           &DAG->getPressureDiff(Cand.SU),
350101095a5dSDimitry Andric           Cand.RPDelta,
350201095a5dSDimitry Andric           DAG->getRegionCriticalPSets(),
350301095a5dSDimitry Andric           DAG->getRegPressure().MaxSetPressure);
350401095a5dSDimitry Andric       } else {
350501095a5dSDimitry Andric         RPTracker.getUpwardPressureDelta(
350601095a5dSDimitry Andric           Cand.SU->getInstr(),
350701095a5dSDimitry Andric           DAG->getPressureDiff(Cand.SU),
350801095a5dSDimitry Andric           Cand.RPDelta,
350901095a5dSDimitry Andric           DAG->getRegionCriticalPSets(),
351001095a5dSDimitry Andric           DAG->getRegPressure().MaxSetPressure);
351101095a5dSDimitry Andric       }
351201095a5dSDimitry Andric     }
351301095a5dSDimitry Andric   }
3514eb11fae6SDimitry Andric   LLVM_DEBUG(if (Cand.RPDelta.Excess.isValid()) dbgs()
3515eb11fae6SDimitry Andric              << "  Try  SU(" << Cand.SU->NodeNum << ") "
3516eb11fae6SDimitry Andric              << TRI->getRegPressureSetName(Cand.RPDelta.Excess.getPSet()) << ":"
3517eb11fae6SDimitry Andric              << Cand.RPDelta.Excess.getUnitInc() << "\n");
351801095a5dSDimitry Andric }
351901095a5dSDimitry Andric 
3520eb11fae6SDimitry Andric /// Apply a set of heuristics to a new candidate. Heuristics are currently
3521522600a2SDimitry Andric /// hierarchical. This may be more efficient than a graduated cost model because
3522522600a2SDimitry Andric /// we don't need to evaluate all aspects of the model for each node in the
3523522600a2SDimitry Andric /// queue. But it's really done to make the heuristics easier to debug and
3524522600a2SDimitry Andric /// statistically analyze.
3525522600a2SDimitry Andric ///
3526522600a2SDimitry Andric /// \param Cand provides the policy and current best candidate.
3527522600a2SDimitry Andric /// \param TryCand refers to the next SUnit candidate, otherwise uninitialized.
352801095a5dSDimitry Andric /// \param Zone describes the scheduled zone that we are extending, or nullptr
3529344a3780SDimitry Andric ///             if Cand is from a different zone than TryCand.
3530344a3780SDimitry Andric /// \return \c true if TryCand is better than Cand (Reason is NOT NoCand)
tryCandidate(SchedCandidate & Cand,SchedCandidate & TryCand,SchedBoundary * Zone) const3531344a3780SDimitry Andric bool GenericScheduler::tryCandidate(SchedCandidate &Cand,
3532522600a2SDimitry Andric                                     SchedCandidate &TryCand,
3533eb11fae6SDimitry Andric                                     SchedBoundary *Zone) const {
3534522600a2SDimitry Andric   // Initialize the candidate if needed.
3535522600a2SDimitry Andric   if (!Cand.isValid()) {
3536522600a2SDimitry Andric     TryCand.Reason = NodeOrder;
3537344a3780SDimitry Andric     return true;
3538522600a2SDimitry Andric   }
353959d6cff9SDimitry Andric 
3540d8e91e46SDimitry Andric   // Bias PhysReg Defs and copies to their uses and defined respectively.
3541d8e91e46SDimitry Andric   if (tryGreater(biasPhysReg(TryCand.SU, TryCand.AtTop),
3542d8e91e46SDimitry Andric                  biasPhysReg(Cand.SU, Cand.AtTop), TryCand, Cand, PhysReg))
3543344a3780SDimitry Andric     return TryCand.Reason != NoCand;
354459d6cff9SDimitry Andric 
35455a5ac124SDimitry Andric   // Avoid exceeding the target's limit.
3546f8af5cf6SDimitry Andric   if (DAG->isTrackingPressure() && tryPressure(TryCand.RPDelta.Excess,
3547f8af5cf6SDimitry Andric                                                Cand.RPDelta.Excess,
3548dd58ef01SDimitry Andric                                                TryCand, Cand, RegExcess, TRI,
3549dd58ef01SDimitry Andric                                                DAG->MF))
3550344a3780SDimitry Andric     return TryCand.Reason != NoCand;
3551522600a2SDimitry Andric 
3552522600a2SDimitry Andric   // Avoid increasing the max critical pressure in the scheduled region.
3553f8af5cf6SDimitry Andric   if (DAG->isTrackingPressure() && tryPressure(TryCand.RPDelta.CriticalMax,
3554f8af5cf6SDimitry Andric                                                Cand.RPDelta.CriticalMax,
3555dd58ef01SDimitry Andric                                                TryCand, Cand, RegCritical, TRI,
3556dd58ef01SDimitry Andric                                                DAG->MF))
3557344a3780SDimitry Andric     return TryCand.Reason != NoCand;
3558f8af5cf6SDimitry Andric 
355901095a5dSDimitry Andric   // We only compare a subset of features when comparing nodes between
356001095a5dSDimitry Andric   // Top and Bottom boundary. Some properties are simply incomparable, in many
356101095a5dSDimitry Andric   // other instances we should only override the other boundary if something
356201095a5dSDimitry Andric   // is a clear good pick on one boundary. Skip heuristics that are more
356301095a5dSDimitry Andric   // "tie-breaking" in nature.
356401095a5dSDimitry Andric   bool SameBoundary = Zone != nullptr;
356501095a5dSDimitry Andric   if (SameBoundary) {
356601095a5dSDimitry Andric     // For loops that are acyclic path limited, aggressively schedule for
3567b915e9e0SDimitry Andric     // latency. Within an single cycle, whenever CurrMOps > 0, allow normal
3568b915e9e0SDimitry Andric     // heuristics to take precedence.
356901095a5dSDimitry Andric     if (Rem.IsAcyclicLatencyLimited && !Zone->getCurrMOps() &&
357001095a5dSDimitry Andric         tryLatency(TryCand, Cand, *Zone))
3571344a3780SDimitry Andric       return TryCand.Reason != NoCand;
3572522600a2SDimitry Andric 
35735ca98fd9SDimitry Andric     // Prioritize instructions that read unbuffered resources by stall cycles.
357401095a5dSDimitry Andric     if (tryLess(Zone->getLatencyStallCycles(TryCand.SU),
357501095a5dSDimitry Andric                 Zone->getLatencyStallCycles(Cand.SU), TryCand, Cand, Stall))
3576344a3780SDimitry Andric       return TryCand.Reason != NoCand;
357701095a5dSDimitry Andric   }
35785ca98fd9SDimitry Andric 
35794a16efa3SDimitry Andric   // Keep clustered nodes together to encourage downstream peephole
35804a16efa3SDimitry Andric   // optimizations which may reduce resource requirements.
35814a16efa3SDimitry Andric   //
35824a16efa3SDimitry Andric   // This is a best effort to set things up for a post-RA pass. Optimizations
35834a16efa3SDimitry Andric   // like generating loads of multiple registers should ideally be done within
35844a16efa3SDimitry Andric   // the scheduler pass by combining the loads during DAG postprocessing.
358501095a5dSDimitry Andric   const SUnit *CandNextClusterSU =
358601095a5dSDimitry Andric     Cand.AtTop ? DAG->getNextClusterSucc() : DAG->getNextClusterPred();
358701095a5dSDimitry Andric   const SUnit *TryCandNextClusterSU =
358801095a5dSDimitry Andric     TryCand.AtTop ? DAG->getNextClusterSucc() : DAG->getNextClusterPred();
358901095a5dSDimitry Andric   if (tryGreater(TryCand.SU == TryCandNextClusterSU,
359001095a5dSDimitry Andric                  Cand.SU == CandNextClusterSU,
35914a16efa3SDimitry Andric                  TryCand, Cand, Cluster))
3592344a3780SDimitry Andric     return TryCand.Reason != NoCand;
359359d6cff9SDimitry Andric 
359401095a5dSDimitry Andric   if (SameBoundary) {
359559d6cff9SDimitry Andric     // Weak edges are for clustering and other constraints.
359601095a5dSDimitry Andric     if (tryLess(getWeakLeft(TryCand.SU, TryCand.AtTop),
359701095a5dSDimitry Andric                 getWeakLeft(Cand.SU, Cand.AtTop),
359801095a5dSDimitry Andric                 TryCand, Cand, Weak))
3599344a3780SDimitry Andric       return TryCand.Reason != NoCand;
36004a16efa3SDimitry Andric   }
360101095a5dSDimitry Andric 
3602f8af5cf6SDimitry Andric   // Avoid increasing the max pressure of the entire region.
3603f8af5cf6SDimitry Andric   if (DAG->isTrackingPressure() && tryPressure(TryCand.RPDelta.CurrentMax,
3604f8af5cf6SDimitry Andric                                                Cand.RPDelta.CurrentMax,
3605dd58ef01SDimitry Andric                                                TryCand, Cand, RegMax, TRI,
3606dd58ef01SDimitry Andric                                                DAG->MF))
3607344a3780SDimitry Andric     return TryCand.Reason != NoCand;
3608f8af5cf6SDimitry Andric 
360901095a5dSDimitry Andric   if (SameBoundary) {
3610522600a2SDimitry Andric     // Avoid critical resource consumption and balance the schedule.
3611522600a2SDimitry Andric     TryCand.initResourceDelta(DAG, SchedModel);
3612522600a2SDimitry Andric     if (tryLess(TryCand.ResDelta.CritResources, Cand.ResDelta.CritResources,
3613522600a2SDimitry Andric                 TryCand, Cand, ResourceReduce))
3614344a3780SDimitry Andric       return TryCand.Reason != NoCand;
3615522600a2SDimitry Andric     if (tryGreater(TryCand.ResDelta.DemandedResources,
3616522600a2SDimitry Andric                    Cand.ResDelta.DemandedResources,
3617522600a2SDimitry Andric                    TryCand, Cand, ResourceDemand))
3618344a3780SDimitry Andric       return TryCand.Reason != NoCand;
3619522600a2SDimitry Andric 
3620522600a2SDimitry Andric     // Avoid serializing long latency dependence chains.
3621f8af5cf6SDimitry Andric     // For acyclic path limited loops, latency was already checked above.
362201095a5dSDimitry Andric     if (!RegionPolicy.DisableLatencyHeuristic && TryCand.Policy.ReduceLatency &&
362301095a5dSDimitry Andric         !Rem.IsAcyclicLatencyLimited && tryLatency(TryCand, Cand, *Zone))
3624344a3780SDimitry Andric       return TryCand.Reason != NoCand;
3625522600a2SDimitry Andric 
3626522600a2SDimitry Andric     // Fall through to original instruction order.
362701095a5dSDimitry Andric     if ((Zone->isTop() && TryCand.SU->NodeNum < Cand.SU->NodeNum)
362801095a5dSDimitry Andric         || (!Zone->isTop() && TryCand.SU->NodeNum > Cand.SU->NodeNum)) {
3629522600a2SDimitry Andric       TryCand.Reason = NodeOrder;
3630344a3780SDimitry Andric       return true;
3631522600a2SDimitry Andric     }
3632522600a2SDimitry Andric   }
3633344a3780SDimitry Andric 
3634344a3780SDimitry Andric   return false;
363501095a5dSDimitry Andric }
363658b69754SDimitry Andric 
3637f8af5cf6SDimitry Andric /// Pick the best candidate from the queue.
363858b69754SDimitry Andric ///
363958b69754SDimitry Andric /// TODO: getMaxPressureDelta results can be mostly cached for each SUnit during
364058b69754SDimitry Andric /// DAG building. To adjust for the current scheduling location we need to
364158b69754SDimitry Andric /// maintain the number of vreg uses remaining to be top-scheduled.
pickNodeFromQueue(SchedBoundary & Zone,const CandPolicy & ZonePolicy,const RegPressureTracker & RPTracker,SchedCandidate & Cand)3642f8af5cf6SDimitry Andric void GenericScheduler::pickNodeFromQueue(SchedBoundary &Zone,
364301095a5dSDimitry Andric                                          const CandPolicy &ZonePolicy,
3644522600a2SDimitry Andric                                          const RegPressureTracker &RPTracker,
3645522600a2SDimitry Andric                                          SchedCandidate &Cand) {
364658b69754SDimitry Andric   // getMaxPressureDelta temporarily modifies the tracker.
364758b69754SDimitry Andric   RegPressureTracker &TempTracker = const_cast<RegPressureTracker&>(RPTracker);
364858b69754SDimitry Andric 
364901095a5dSDimitry Andric   ReadyQueue &Q = Zone.Available;
365008bbd35aSDimitry Andric   for (SUnit *SU : Q) {
365158b69754SDimitry Andric 
365201095a5dSDimitry Andric     SchedCandidate TryCand(ZonePolicy);
365308bbd35aSDimitry Andric     initCandidate(TryCand, SU, Zone.isTop(), RPTracker, TempTracker);
365401095a5dSDimitry Andric     // Pass SchedBoundary only when comparing nodes from the same boundary.
365501095a5dSDimitry Andric     SchedBoundary *ZoneArg = Cand.AtTop == TryCand.AtTop ? &Zone : nullptr;
3656344a3780SDimitry Andric     if (tryCandidate(Cand, TryCand, ZoneArg)) {
3657522600a2SDimitry Andric       // Initialize resource delta if needed in case future heuristics query it.
3658522600a2SDimitry Andric       if (TryCand.ResDelta == SchedResourceDelta())
3659522600a2SDimitry Andric         TryCand.initResourceDelta(DAG, SchedModel);
3660522600a2SDimitry Andric       Cand.setBest(TryCand);
3661eb11fae6SDimitry Andric       LLVM_DEBUG(traceCandidate(Cand));
366258b69754SDimitry Andric     }
366358b69754SDimitry Andric   }
3664522600a2SDimitry Andric }
366558b69754SDimitry Andric 
366658b69754SDimitry Andric /// Pick the best candidate node from either the top or bottom queue.
pickNodeBidirectional(bool & IsTopNode)3667f8af5cf6SDimitry Andric SUnit *GenericScheduler::pickNodeBidirectional(bool &IsTopNode) {
366858b69754SDimitry Andric   // Schedule as far as possible in the direction of no choice. This is most
366958b69754SDimitry Andric   // efficient, but also provides the best heuristics for CriticalPSets.
367058b69754SDimitry Andric   if (SUnit *SU = Bot.pickOnlyChoice()) {
367158b69754SDimitry Andric     IsTopNode = false;
367201095a5dSDimitry Andric     tracePick(Only1, false);
367358b69754SDimitry Andric     return SU;
367458b69754SDimitry Andric   }
367558b69754SDimitry Andric   if (SUnit *SU = Top.pickOnlyChoice()) {
367658b69754SDimitry Andric     IsTopNode = true;
367701095a5dSDimitry Andric     tracePick(Only1, true);
367858b69754SDimitry Andric     return SU;
367958b69754SDimitry Andric   }
36805ca98fd9SDimitry Andric   // Set the bottom-up policy based on the state of the current bottom zone and
36815ca98fd9SDimitry Andric   // the instructions outside the zone, including the top zone.
368201095a5dSDimitry Andric   CandPolicy BotPolicy;
368301095a5dSDimitry Andric   setPolicy(BotPolicy, /*IsPostRA=*/false, Bot, &Top);
36845ca98fd9SDimitry Andric   // Set the top-down policy based on the state of the current top zone and
36855ca98fd9SDimitry Andric   // the instructions outside the zone, including the bottom zone.
368601095a5dSDimitry Andric   CandPolicy TopPolicy;
368701095a5dSDimitry Andric   setPolicy(TopPolicy, /*IsPostRA=*/false, Top, &Bot);
3688522600a2SDimitry Andric 
368901095a5dSDimitry Andric   // See if BotCand is still valid (because we previously scheduled from Top).
3690eb11fae6SDimitry Andric   LLVM_DEBUG(dbgs() << "Picking from Bot:\n");
369101095a5dSDimitry Andric   if (!BotCand.isValid() || BotCand.SU->isScheduled ||
369201095a5dSDimitry Andric       BotCand.Policy != BotPolicy) {
369301095a5dSDimitry Andric     BotCand.reset(CandPolicy());
369401095a5dSDimitry Andric     pickNodeFromQueue(Bot, BotPolicy, DAG->getBotRPTracker(), BotCand);
3695522600a2SDimitry Andric     assert(BotCand.Reason != NoCand && "failed to find the first candidate");
369601095a5dSDimitry Andric   } else {
3697eb11fae6SDimitry Andric     LLVM_DEBUG(traceCandidate(BotCand));
369801095a5dSDimitry Andric #ifndef NDEBUG
369901095a5dSDimitry Andric     if (VerifyScheduling) {
370001095a5dSDimitry Andric       SchedCandidate TCand;
370101095a5dSDimitry Andric       TCand.reset(CandPolicy());
370201095a5dSDimitry Andric       pickNodeFromQueue(Bot, BotPolicy, DAG->getBotRPTracker(), TCand);
370301095a5dSDimitry Andric       assert(TCand.SU == BotCand.SU &&
370401095a5dSDimitry Andric              "Last pick result should correspond to re-picking right now");
370558b69754SDimitry Andric     }
370601095a5dSDimitry Andric #endif
370701095a5dSDimitry Andric   }
370801095a5dSDimitry Andric 
370958b69754SDimitry Andric   // Check if the top Q has a better candidate.
3710eb11fae6SDimitry Andric   LLVM_DEBUG(dbgs() << "Picking from Top:\n");
371101095a5dSDimitry Andric   if (!TopCand.isValid() || TopCand.SU->isScheduled ||
371201095a5dSDimitry Andric       TopCand.Policy != TopPolicy) {
371301095a5dSDimitry Andric     TopCand.reset(CandPolicy());
371401095a5dSDimitry Andric     pickNodeFromQueue(Top, TopPolicy, DAG->getTopRPTracker(), TopCand);
3715522600a2SDimitry Andric     assert(TopCand.Reason != NoCand && "failed to find the first candidate");
371601095a5dSDimitry Andric   } else {
3717eb11fae6SDimitry Andric     LLVM_DEBUG(traceCandidate(TopCand));
371801095a5dSDimitry Andric #ifndef NDEBUG
371901095a5dSDimitry Andric     if (VerifyScheduling) {
372001095a5dSDimitry Andric       SchedCandidate TCand;
372101095a5dSDimitry Andric       TCand.reset(CandPolicy());
372201095a5dSDimitry Andric       pickNodeFromQueue(Top, TopPolicy, DAG->getTopRPTracker(), TCand);
372301095a5dSDimitry Andric       assert(TCand.SU == TopCand.SU &&
372401095a5dSDimitry Andric              "Last pick result should correspond to re-picking right now");
372558b69754SDimitry Andric     }
372601095a5dSDimitry Andric #endif
372701095a5dSDimitry Andric   }
372801095a5dSDimitry Andric 
372901095a5dSDimitry Andric   // Pick best from BotCand and TopCand.
373001095a5dSDimitry Andric   assert(BotCand.isValid());
373101095a5dSDimitry Andric   assert(TopCand.isValid());
373201095a5dSDimitry Andric   SchedCandidate Cand = BotCand;
373301095a5dSDimitry Andric   TopCand.Reason = NoCand;
3734344a3780SDimitry Andric   if (tryCandidate(Cand, TopCand, nullptr)) {
373501095a5dSDimitry Andric     Cand.setBest(TopCand);
3736eb11fae6SDimitry Andric     LLVM_DEBUG(traceCandidate(Cand));
373701095a5dSDimitry Andric   }
373801095a5dSDimitry Andric 
373901095a5dSDimitry Andric   IsTopNode = Cand.AtTop;
374001095a5dSDimitry Andric   tracePick(Cand);
374101095a5dSDimitry Andric   return Cand.SU;
374258b69754SDimitry Andric }
374358b69754SDimitry Andric 
374458b69754SDimitry Andric /// Pick the best node to balance the schedule. Implements MachineSchedStrategy.
pickNode(bool & IsTopNode)3745f8af5cf6SDimitry Andric SUnit *GenericScheduler::pickNode(bool &IsTopNode) {
374658b69754SDimitry Andric   if (DAG->top() == DAG->bottom()) {
374758b69754SDimitry Andric     assert(Top.Available.empty() && Top.Pending.empty() &&
374858b69754SDimitry Andric            Bot.Available.empty() && Bot.Pending.empty() && "ReadyQ garbage");
37495ca98fd9SDimitry Andric     return nullptr;
375058b69754SDimitry Andric   }
375158b69754SDimitry Andric   SUnit *SU;
3752522600a2SDimitry Andric   do {
3753f8af5cf6SDimitry Andric     if (RegionPolicy.OnlyTopDown) {
375458b69754SDimitry Andric       SU = Top.pickOnlyChoice();
375558b69754SDimitry Andric       if (!SU) {
3756522600a2SDimitry Andric         CandPolicy NoPolicy;
375701095a5dSDimitry Andric         TopCand.reset(NoPolicy);
375801095a5dSDimitry Andric         pickNodeFromQueue(Top, NoPolicy, DAG->getTopRPTracker(), TopCand);
3759f8af5cf6SDimitry Andric         assert(TopCand.Reason != NoCand && "failed to find a candidate");
376001095a5dSDimitry Andric         tracePick(TopCand);
376158b69754SDimitry Andric         SU = TopCand.SU;
376258b69754SDimitry Andric       }
376358b69754SDimitry Andric       IsTopNode = true;
376401095a5dSDimitry Andric     } else if (RegionPolicy.OnlyBottomUp) {
376558b69754SDimitry Andric       SU = Bot.pickOnlyChoice();
376658b69754SDimitry Andric       if (!SU) {
3767522600a2SDimitry Andric         CandPolicy NoPolicy;
376801095a5dSDimitry Andric         BotCand.reset(NoPolicy);
376901095a5dSDimitry Andric         pickNodeFromQueue(Bot, NoPolicy, DAG->getBotRPTracker(), BotCand);
3770f8af5cf6SDimitry Andric         assert(BotCand.Reason != NoCand && "failed to find a candidate");
377101095a5dSDimitry Andric         tracePick(BotCand);
377258b69754SDimitry Andric         SU = BotCand.SU;
377358b69754SDimitry Andric       }
377463faed5bSDimitry Andric       IsTopNode = false;
377501095a5dSDimitry Andric     } else {
3776522600a2SDimitry Andric       SU = pickNodeBidirectional(IsTopNode);
377763faed5bSDimitry Andric     }
3778522600a2SDimitry Andric   } while (SU->isScheduled);
3779522600a2SDimitry Andric 
3780ac9a064cSDimitry Andric   // If IsTopNode, then SU is in Top.Available and must be removed. Otherwise,
3781ac9a064cSDimitry Andric   // if isTopReady(), then SU is in either Top.Available or Top.Pending.
3782ac9a064cSDimitry Andric   // If !IsTopNode, then SU is in Bot.Available and must be removed. Otherwise,
3783ac9a064cSDimitry Andric   // if isBottomReady(), then SU is in either Bot.Available or Bot.Pending.
3784ac9a064cSDimitry Andric   //
3785ac9a064cSDimitry Andric   // It is coincidental when !IsTopNode && isTopReady or when IsTopNode &&
3786ac9a064cSDimitry Andric   // isBottomReady. That is, it didn't factor into the decision to choose SU
3787ac9a064cSDimitry Andric   // because it isTopReady or isBottomReady, respectively. In fact, if the
3788ac9a064cSDimitry Andric   // RegionPolicy is OnlyTopDown or OnlyBottomUp, then the Bot queues and Top
3789ac9a064cSDimitry Andric   // queues respectivley contain the original roots and don't get updated when
3790ac9a064cSDimitry Andric   // picking a node. So if SU isTopReady on a OnlyBottomUp pick, then it was
3791ac9a064cSDimitry Andric   // because we schduled everything but the top roots. Conversley, if SU
3792ac9a064cSDimitry Andric   // isBottomReady on OnlyTopDown, then it was because we scheduled everything
3793ac9a064cSDimitry Andric   // but the bottom roots. If its in a queue even coincidentally, it should be
3794ac9a064cSDimitry Andric   // removed so it does not get re-picked in a subsequent pickNode call.
379558b69754SDimitry Andric   if (SU->isTopReady())
379658b69754SDimitry Andric     Top.removeReady(SU);
379758b69754SDimitry Andric   if (SU->isBottomReady())
379858b69754SDimitry Andric     Bot.removeReady(SU);
379958b69754SDimitry Andric 
3800eb11fae6SDimitry Andric   LLVM_DEBUG(dbgs() << "Scheduling SU(" << SU->NodeNum << ") "
3801eb11fae6SDimitry Andric                     << *SU->getInstr());
380263faed5bSDimitry Andric   return SU;
380363faed5bSDimitry Andric }
380463faed5bSDimitry Andric 
reschedulePhysReg(SUnit * SU,bool isTop)3805d8e91e46SDimitry Andric void GenericScheduler::reschedulePhysReg(SUnit *SU, bool isTop) {
380659d6cff9SDimitry Andric   MachineBasicBlock::iterator InsertPos = SU->getInstr();
380759d6cff9SDimitry Andric   if (!isTop)
380859d6cff9SDimitry Andric     ++InsertPos;
380959d6cff9SDimitry Andric   SmallVectorImpl<SDep> &Deps = isTop ? SU->Preds : SU->Succs;
381059d6cff9SDimitry Andric 
381159d6cff9SDimitry Andric   // Find already scheduled copies with a single physreg dependence and move
381259d6cff9SDimitry Andric   // them just above the scheduled instruction.
381308bbd35aSDimitry Andric   for (SDep &Dep : Deps) {
38141d5ae102SDimitry Andric     if (Dep.getKind() != SDep::Data ||
38151d5ae102SDimitry Andric         !Register::isPhysicalRegister(Dep.getReg()))
381659d6cff9SDimitry Andric       continue;
381708bbd35aSDimitry Andric     SUnit *DepSU = Dep.getSUnit();
381859d6cff9SDimitry Andric     if (isTop ? DepSU->Succs.size() > 1 : DepSU->Preds.size() > 1)
381959d6cff9SDimitry Andric       continue;
382059d6cff9SDimitry Andric     MachineInstr *Copy = DepSU->getInstr();
3821d8e91e46SDimitry Andric     if (!Copy->isCopy() && !Copy->isMoveImmediate())
382259d6cff9SDimitry Andric       continue;
3823eb11fae6SDimitry Andric     LLVM_DEBUG(dbgs() << "  Rescheduling physreg copy ";
3824d8e91e46SDimitry Andric                DAG->dumpNode(*Dep.getSUnit()));
382559d6cff9SDimitry Andric     DAG->moveInstruction(Copy, InsertPos);
382659d6cff9SDimitry Andric   }
382759d6cff9SDimitry Andric }
382859d6cff9SDimitry Andric 
382958b69754SDimitry Andric /// Update the scheduler's state after scheduling a node. This is the same node
38305ca98fd9SDimitry Andric /// that was just returned by pickNode(). However, ScheduleDAGMILive needs to
38315ca98fd9SDimitry Andric /// update it's state based on the current cycle before MachineSchedStrategy
38325ca98fd9SDimitry Andric /// does.
383359d6cff9SDimitry Andric ///
383459d6cff9SDimitry Andric /// FIXME: Eventually, we may bundle physreg copies rather than rescheduling
3835d8e91e46SDimitry Andric /// them here. See comments in biasPhysReg.
schedNode(SUnit * SU,bool IsTopNode)3836f8af5cf6SDimitry Andric void GenericScheduler::schedNode(SUnit *SU, bool IsTopNode) {
383758b69754SDimitry Andric   if (IsTopNode) {
38385ca98fd9SDimitry Andric     SU->TopReadyCycle = std::max(SU->TopReadyCycle, Top.getCurrCycle());
383958b69754SDimitry Andric     Top.bumpNode(SU);
384059d6cff9SDimitry Andric     if (SU->hasPhysRegUses)
3841d8e91e46SDimitry Andric       reschedulePhysReg(SU, true);
384201095a5dSDimitry Andric   } else {
38435ca98fd9SDimitry Andric     SU->BotReadyCycle = std::max(SU->BotReadyCycle, Bot.getCurrCycle());
384458b69754SDimitry Andric     Bot.bumpNode(SU);
384559d6cff9SDimitry Andric     if (SU->hasPhysRegDefs)
3846d8e91e46SDimitry Andric       reschedulePhysReg(SU, false);
384763faed5bSDimitry Andric   }
384858b69754SDimitry Andric }
384963faed5bSDimitry Andric 
385063faed5bSDimitry Andric /// Create the standard converging machine scheduler. This will be used as the
385163faed5bSDimitry Andric /// default scheduler if the target does not set a default.
createGenericSchedLive(MachineSchedContext * C)3852b915e9e0SDimitry Andric ScheduleDAGMILive *llvm::createGenericSchedLive(MachineSchedContext *C) {
385371d5a254SDimitry Andric   ScheduleDAGMILive *DAG =
38541d5ae102SDimitry Andric       new ScheduleDAGMILive(C, std::make_unique<GenericScheduler>(C));
38554a16efa3SDimitry Andric   // Register DAG post-processors.
385659d6cff9SDimitry Andric   //
385759d6cff9SDimitry Andric   // FIXME: extend the mutation API to allow earlier mutations to instantiate
385859d6cff9SDimitry Andric   // data and pass it to later mutations. Have a single mutation that gathers
385959d6cff9SDimitry Andric   // the interesting nodes in one pass.
3860b915e9e0SDimitry Andric   DAG->addMutation(createCopyConstrainDAGMutation(DAG->TII, DAG->TRI));
3861ac9a064cSDimitry Andric 
3862ac9a064cSDimitry Andric   const TargetSubtargetInfo &STI = C->MF->getSubtarget();
3863ac9a064cSDimitry Andric   // Add MacroFusion mutation if fusions are not empty.
3864ac9a064cSDimitry Andric   const auto &MacroFusions = STI.getMacroFusions();
3865ac9a064cSDimitry Andric   if (!MacroFusions.empty())
3866ac9a064cSDimitry Andric     DAG->addMutation(createMacroFusionDAGMutation(MacroFusions));
38674a16efa3SDimitry Andric   return DAG;
386863faed5bSDimitry Andric }
38695ca98fd9SDimitry Andric 
createConvergingSched(MachineSchedContext * C)3870b60736ecSDimitry Andric static ScheduleDAGInstrs *createConvergingSched(MachineSchedContext *C) {
3871b915e9e0SDimitry Andric   return createGenericSchedLive(C);
3872b915e9e0SDimitry Andric }
3873b915e9e0SDimitry Andric 
387463faed5bSDimitry Andric static MachineSchedRegistry
3875f8af5cf6SDimitry Andric GenericSchedRegistry("converge", "Standard converging scheduler.",
3876b60736ecSDimitry Andric                      createConvergingSched);
38775ca98fd9SDimitry Andric 
38785ca98fd9SDimitry Andric //===----------------------------------------------------------------------===//
38795ca98fd9SDimitry Andric // PostGenericScheduler - Generic PostRA implementation of MachineSchedStrategy.
38805ca98fd9SDimitry Andric //===----------------------------------------------------------------------===//
38815ca98fd9SDimitry Andric 
initialize(ScheduleDAGMI * Dag)38825ca98fd9SDimitry Andric void PostGenericScheduler::initialize(ScheduleDAGMI *Dag) {
38835ca98fd9SDimitry Andric   DAG = Dag;
38845ca98fd9SDimitry Andric   SchedModel = DAG->getSchedModel();
38855ca98fd9SDimitry Andric   TRI = DAG->TRI;
38865ca98fd9SDimitry Andric 
38875ca98fd9SDimitry Andric   Rem.init(DAG, SchedModel);
38885ca98fd9SDimitry Andric   Top.init(DAG, SchedModel, &Rem);
3889ac9a064cSDimitry Andric   Bot.init(DAG, SchedModel, &Rem);
38905ca98fd9SDimitry Andric 
38915ca98fd9SDimitry Andric   // Initialize the HazardRecognizers. If itineraries don't exist, are empty,
38925ca98fd9SDimitry Andric   // or are disabled, then these HazardRecs will be disabled.
38935ca98fd9SDimitry Andric   const InstrItineraryData *Itin = SchedModel->getInstrItineraries();
38945ca98fd9SDimitry Andric   if (!Top.HazardRec) {
3895ac9a064cSDimitry Andric     Top.HazardRec = DAG->TII->CreateTargetMIHazardRecognizer(Itin, DAG);
3896ac9a064cSDimitry Andric   }
3897ac9a064cSDimitry Andric   if (!Bot.HazardRec) {
3898ac9a064cSDimitry Andric     Bot.HazardRec = DAG->TII->CreateTargetMIHazardRecognizer(Itin, DAG);
3899ac9a064cSDimitry Andric   }
3900ac9a064cSDimitry Andric }
3901ac9a064cSDimitry Andric 
initPolicy(MachineBasicBlock::iterator Begin,MachineBasicBlock::iterator End,unsigned NumRegionInstrs)3902ac9a064cSDimitry Andric void PostGenericScheduler::initPolicy(MachineBasicBlock::iterator Begin,
3903ac9a064cSDimitry Andric                                       MachineBasicBlock::iterator End,
3904ac9a064cSDimitry Andric                                       unsigned NumRegionInstrs) {
3905ac9a064cSDimitry Andric   if (PostRADirection == MISchedPostRASched::TopDown) {
3906ac9a064cSDimitry Andric     RegionPolicy.OnlyTopDown = true;
3907ac9a064cSDimitry Andric     RegionPolicy.OnlyBottomUp = false;
3908ac9a064cSDimitry Andric   } else if (PostRADirection == MISchedPostRASched::BottomUp) {
3909ac9a064cSDimitry Andric     RegionPolicy.OnlyTopDown = false;
3910ac9a064cSDimitry Andric     RegionPolicy.OnlyBottomUp = true;
3911ac9a064cSDimitry Andric   } else if (PostRADirection == MISchedPostRASched::Bidirectional) {
3912ac9a064cSDimitry Andric     RegionPolicy.OnlyBottomUp = false;
3913ac9a064cSDimitry Andric     RegionPolicy.OnlyTopDown = false;
39145ca98fd9SDimitry Andric   }
39155ca98fd9SDimitry Andric }
39165ca98fd9SDimitry Andric 
registerRoots()39175ca98fd9SDimitry Andric void PostGenericScheduler::registerRoots() {
39185ca98fd9SDimitry Andric   Rem.CriticalPath = DAG->ExitSU.getDepth();
39195ca98fd9SDimitry Andric 
39205ca98fd9SDimitry Andric   // Some roots may not feed into ExitSU. Check all of them in case.
3921ac9a064cSDimitry Andric   for (const SUnit *SU : Bot.Available) {
392208bbd35aSDimitry Andric     if (SU->getDepth() > Rem.CriticalPath)
392308bbd35aSDimitry Andric       Rem.CriticalPath = SU->getDepth();
39245ca98fd9SDimitry Andric   }
3925eb11fae6SDimitry Andric   LLVM_DEBUG(dbgs() << "Critical Path: (PGS-RR) " << Rem.CriticalPath << '\n');
392667c32a98SDimitry Andric   if (DumpCriticalPathLength) {
392767c32a98SDimitry Andric     errs() << "Critical Path(PGS-RR ): " << Rem.CriticalPath << " \n";
392867c32a98SDimitry Andric   }
39295ca98fd9SDimitry Andric }
39305ca98fd9SDimitry Andric 
3931eb11fae6SDimitry Andric /// Apply a set of heuristics to a new candidate for PostRA scheduling.
39325ca98fd9SDimitry Andric ///
39335ca98fd9SDimitry Andric /// \param Cand provides the policy and current best candidate.
39345ca98fd9SDimitry Andric /// \param TryCand refers to the next SUnit candidate, otherwise uninitialized.
3935344a3780SDimitry Andric /// \return \c true if TryCand is better than Cand (Reason is NOT NoCand)
tryCandidate(SchedCandidate & Cand,SchedCandidate & TryCand)3936344a3780SDimitry Andric bool PostGenericScheduler::tryCandidate(SchedCandidate &Cand,
39375ca98fd9SDimitry Andric                                         SchedCandidate &TryCand) {
39385ca98fd9SDimitry Andric   // Initialize the candidate if needed.
39395ca98fd9SDimitry Andric   if (!Cand.isValid()) {
39405ca98fd9SDimitry Andric     TryCand.Reason = NodeOrder;
3941344a3780SDimitry Andric     return true;
39425ca98fd9SDimitry Andric   }
39435ca98fd9SDimitry Andric 
39445ca98fd9SDimitry Andric   // Prioritize instructions that read unbuffered resources by stall cycles.
39455ca98fd9SDimitry Andric   if (tryLess(Top.getLatencyStallCycles(TryCand.SU),
39465ca98fd9SDimitry Andric               Top.getLatencyStallCycles(Cand.SU), TryCand, Cand, Stall))
3947344a3780SDimitry Andric     return TryCand.Reason != NoCand;
39485ca98fd9SDimitry Andric 
3949ab44ce3dSDimitry Andric   // Keep clustered nodes together.
3950ab44ce3dSDimitry Andric   if (tryGreater(TryCand.SU == DAG->getNextClusterSucc(),
3951ab44ce3dSDimitry Andric                  Cand.SU == DAG->getNextClusterSucc(),
3952ab44ce3dSDimitry Andric                  TryCand, Cand, Cluster))
3953344a3780SDimitry Andric     return TryCand.Reason != NoCand;
3954ab44ce3dSDimitry Andric 
39555ca98fd9SDimitry Andric   // Avoid critical resource consumption and balance the schedule.
39565ca98fd9SDimitry Andric   if (tryLess(TryCand.ResDelta.CritResources, Cand.ResDelta.CritResources,
39575ca98fd9SDimitry Andric               TryCand, Cand, ResourceReduce))
3958344a3780SDimitry Andric     return TryCand.Reason != NoCand;
39595ca98fd9SDimitry Andric   if (tryGreater(TryCand.ResDelta.DemandedResources,
39605ca98fd9SDimitry Andric                  Cand.ResDelta.DemandedResources,
39615ca98fd9SDimitry Andric                  TryCand, Cand, ResourceDemand))
3962344a3780SDimitry Andric     return TryCand.Reason != NoCand;
39635ca98fd9SDimitry Andric 
39645ca98fd9SDimitry Andric   // Avoid serializing long latency dependence chains.
39655ca98fd9SDimitry Andric   if (Cand.Policy.ReduceLatency && tryLatency(TryCand, Cand, Top)) {
3966344a3780SDimitry Andric     return TryCand.Reason != NoCand;
39675ca98fd9SDimitry Andric   }
39685ca98fd9SDimitry Andric 
39695ca98fd9SDimitry Andric   // Fall through to original instruction order.
3970344a3780SDimitry Andric   if (TryCand.SU->NodeNum < Cand.SU->NodeNum) {
39715ca98fd9SDimitry Andric     TryCand.Reason = NodeOrder;
3972344a3780SDimitry Andric     return true;
3973344a3780SDimitry Andric   }
3974344a3780SDimitry Andric 
3975344a3780SDimitry Andric   return false;
39765ca98fd9SDimitry Andric }
39775ca98fd9SDimitry Andric 
pickNodeFromQueue(SchedBoundary & Zone,SchedCandidate & Cand)3978ac9a064cSDimitry Andric void PostGenericScheduler::pickNodeFromQueue(SchedBoundary &Zone,
3979ac9a064cSDimitry Andric                                              SchedCandidate &Cand) {
3980ac9a064cSDimitry Andric   ReadyQueue &Q = Zone.Available;
398108bbd35aSDimitry Andric   for (SUnit *SU : Q) {
39825ca98fd9SDimitry Andric     SchedCandidate TryCand(Cand.Policy);
398308bbd35aSDimitry Andric     TryCand.SU = SU;
3984ac9a064cSDimitry Andric     TryCand.AtTop = Zone.isTop();
39855ca98fd9SDimitry Andric     TryCand.initResourceDelta(DAG, SchedModel);
3986344a3780SDimitry Andric     if (tryCandidate(Cand, TryCand)) {
39875ca98fd9SDimitry Andric       Cand.setBest(TryCand);
3988eb11fae6SDimitry Andric       LLVM_DEBUG(traceCandidate(Cand));
39895ca98fd9SDimitry Andric     }
39905ca98fd9SDimitry Andric   }
39915ca98fd9SDimitry Andric }
39925ca98fd9SDimitry Andric 
3993ac9a064cSDimitry Andric /// Pick the best candidate node from either the top or bottom queue.
pickNodeBidirectional(bool & IsTopNode)3994ac9a064cSDimitry Andric SUnit *PostGenericScheduler::pickNodeBidirectional(bool &IsTopNode) {
3995ac9a064cSDimitry Andric   // FIXME: This is similiar to GenericScheduler::pickNodeBidirectional. Factor
3996ac9a064cSDimitry Andric   // out common parts.
3997ac9a064cSDimitry Andric 
3998ac9a064cSDimitry Andric   // Schedule as far as possible in the direction of no choice. This is most
3999ac9a064cSDimitry Andric   // efficient, but also provides the best heuristics for CriticalPSets.
4000ac9a064cSDimitry Andric   if (SUnit *SU = Bot.pickOnlyChoice()) {
4001ac9a064cSDimitry Andric     IsTopNode = false;
4002ac9a064cSDimitry Andric     tracePick(Only1, false);
4003ac9a064cSDimitry Andric     return SU;
4004ac9a064cSDimitry Andric   }
4005ac9a064cSDimitry Andric   if (SUnit *SU = Top.pickOnlyChoice()) {
4006ac9a064cSDimitry Andric     IsTopNode = true;
4007ac9a064cSDimitry Andric     tracePick(Only1, true);
4008ac9a064cSDimitry Andric     return SU;
4009ac9a064cSDimitry Andric   }
4010ac9a064cSDimitry Andric   // Set the bottom-up policy based on the state of the current bottom zone and
4011ac9a064cSDimitry Andric   // the instructions outside the zone, including the top zone.
4012ac9a064cSDimitry Andric   CandPolicy BotPolicy;
4013ac9a064cSDimitry Andric   setPolicy(BotPolicy, /*IsPostRA=*/true, Bot, &Top);
4014ac9a064cSDimitry Andric   // Set the top-down policy based on the state of the current top zone and
4015ac9a064cSDimitry Andric   // the instructions outside the zone, including the bottom zone.
4016ac9a064cSDimitry Andric   CandPolicy TopPolicy;
4017ac9a064cSDimitry Andric   setPolicy(TopPolicy, /*IsPostRA=*/true, Top, &Bot);
4018ac9a064cSDimitry Andric 
4019ac9a064cSDimitry Andric   // See if BotCand is still valid (because we previously scheduled from Top).
4020ac9a064cSDimitry Andric   LLVM_DEBUG(dbgs() << "Picking from Bot:\n");
4021ac9a064cSDimitry Andric   if (!BotCand.isValid() || BotCand.SU->isScheduled ||
4022ac9a064cSDimitry Andric       BotCand.Policy != BotPolicy) {
4023ac9a064cSDimitry Andric     BotCand.reset(CandPolicy());
4024ac9a064cSDimitry Andric     pickNodeFromQueue(Bot, BotCand);
4025ac9a064cSDimitry Andric     assert(BotCand.Reason != NoCand && "failed to find the first candidate");
4026ac9a064cSDimitry Andric   } else {
4027ac9a064cSDimitry Andric     LLVM_DEBUG(traceCandidate(BotCand));
4028ac9a064cSDimitry Andric #ifndef NDEBUG
4029ac9a064cSDimitry Andric     if (VerifyScheduling) {
4030ac9a064cSDimitry Andric       SchedCandidate TCand;
4031ac9a064cSDimitry Andric       TCand.reset(CandPolicy());
4032ac9a064cSDimitry Andric       pickNodeFromQueue(Bot, BotCand);
4033ac9a064cSDimitry Andric       assert(TCand.SU == BotCand.SU &&
4034ac9a064cSDimitry Andric              "Last pick result should correspond to re-picking right now");
4035ac9a064cSDimitry Andric     }
4036ac9a064cSDimitry Andric #endif
4037ac9a064cSDimitry Andric   }
4038ac9a064cSDimitry Andric 
4039ac9a064cSDimitry Andric   // Check if the top Q has a better candidate.
4040ac9a064cSDimitry Andric   LLVM_DEBUG(dbgs() << "Picking from Top:\n");
4041ac9a064cSDimitry Andric   if (!TopCand.isValid() || TopCand.SU->isScheduled ||
4042ac9a064cSDimitry Andric       TopCand.Policy != TopPolicy) {
4043ac9a064cSDimitry Andric     TopCand.reset(CandPolicy());
4044ac9a064cSDimitry Andric     pickNodeFromQueue(Top, TopCand);
4045ac9a064cSDimitry Andric     assert(TopCand.Reason != NoCand && "failed to find the first candidate");
4046ac9a064cSDimitry Andric   } else {
4047ac9a064cSDimitry Andric     LLVM_DEBUG(traceCandidate(TopCand));
4048ac9a064cSDimitry Andric #ifndef NDEBUG
4049ac9a064cSDimitry Andric     if (VerifyScheduling) {
4050ac9a064cSDimitry Andric       SchedCandidate TCand;
4051ac9a064cSDimitry Andric       TCand.reset(CandPolicy());
4052ac9a064cSDimitry Andric       pickNodeFromQueue(Top, TopCand);
4053ac9a064cSDimitry Andric       assert(TCand.SU == TopCand.SU &&
4054ac9a064cSDimitry Andric              "Last pick result should correspond to re-picking right now");
4055ac9a064cSDimitry Andric     }
4056ac9a064cSDimitry Andric #endif
4057ac9a064cSDimitry Andric   }
4058ac9a064cSDimitry Andric 
4059ac9a064cSDimitry Andric   // Pick best from BotCand and TopCand.
4060ac9a064cSDimitry Andric   assert(BotCand.isValid());
4061ac9a064cSDimitry Andric   assert(TopCand.isValid());
4062ac9a064cSDimitry Andric   SchedCandidate Cand = BotCand;
4063ac9a064cSDimitry Andric   TopCand.Reason = NoCand;
4064ac9a064cSDimitry Andric   if (tryCandidate(Cand, TopCand)) {
4065ac9a064cSDimitry Andric     Cand.setBest(TopCand);
4066ac9a064cSDimitry Andric     LLVM_DEBUG(traceCandidate(Cand));
4067ac9a064cSDimitry Andric   }
4068ac9a064cSDimitry Andric 
4069ac9a064cSDimitry Andric   IsTopNode = Cand.AtTop;
4070ac9a064cSDimitry Andric   tracePick(Cand);
4071ac9a064cSDimitry Andric   return Cand.SU;
4072ac9a064cSDimitry Andric }
4073ac9a064cSDimitry Andric 
40745ca98fd9SDimitry Andric /// Pick the next node to schedule.
pickNode(bool & IsTopNode)40755ca98fd9SDimitry Andric SUnit *PostGenericScheduler::pickNode(bool &IsTopNode) {
40765ca98fd9SDimitry Andric   if (DAG->top() == DAG->bottom()) {
4077ac9a064cSDimitry Andric     assert(Top.Available.empty() && Top.Pending.empty() &&
4078ac9a064cSDimitry Andric            Bot.Available.empty() && Bot.Pending.empty() && "ReadyQ garbage");
40795ca98fd9SDimitry Andric     return nullptr;
40805ca98fd9SDimitry Andric   }
40815ca98fd9SDimitry Andric   SUnit *SU;
40825ca98fd9SDimitry Andric   do {
4083ac9a064cSDimitry Andric     if (RegionPolicy.OnlyBottomUp) {
4084ac9a064cSDimitry Andric       SU = Bot.pickOnlyChoice();
4085ac9a064cSDimitry Andric       if (SU) {
4086ac9a064cSDimitry Andric         tracePick(Only1, true);
4087ac9a064cSDimitry Andric       } else {
4088ac9a064cSDimitry Andric         CandPolicy NoPolicy;
4089ac9a064cSDimitry Andric         BotCand.reset(NoPolicy);
4090ac9a064cSDimitry Andric         // Set the bottom-up policy based on the state of the current bottom
4091ac9a064cSDimitry Andric         // zone and the instructions outside the zone, including the top zone.
4092ac9a064cSDimitry Andric         setPolicy(BotCand.Policy, /*IsPostRA=*/true, Bot, nullptr);
4093ac9a064cSDimitry Andric         pickNodeFromQueue(Bot, BotCand);
4094ac9a064cSDimitry Andric         assert(BotCand.Reason != NoCand && "failed to find a candidate");
4095ac9a064cSDimitry Andric         tracePick(BotCand);
4096ac9a064cSDimitry Andric         SU = BotCand.SU;
4097ac9a064cSDimitry Andric       }
4098ac9a064cSDimitry Andric       IsTopNode = false;
4099ac9a064cSDimitry Andric     } else if (RegionPolicy.OnlyTopDown) {
41005ca98fd9SDimitry Andric       SU = Top.pickOnlyChoice();
410101095a5dSDimitry Andric       if (SU) {
410201095a5dSDimitry Andric         tracePick(Only1, true);
410301095a5dSDimitry Andric       } else {
41045ca98fd9SDimitry Andric         CandPolicy NoPolicy;
4105ac9a064cSDimitry Andric         TopCand.reset(NoPolicy);
4106ac9a064cSDimitry Andric         // Set the top-down policy based on the state of the current top zone
4107ac9a064cSDimitry Andric         // and the instructions outside the zone, including the bottom zone.
41085ca98fd9SDimitry Andric         setPolicy(TopCand.Policy, /*IsPostRA=*/true, Top, nullptr);
4109ac9a064cSDimitry Andric         pickNodeFromQueue(Top, TopCand);
41105ca98fd9SDimitry Andric         assert(TopCand.Reason != NoCand && "failed to find a candidate");
411101095a5dSDimitry Andric         tracePick(TopCand);
41125ca98fd9SDimitry Andric         SU = TopCand.SU;
41135ca98fd9SDimitry Andric       }
4114ac9a064cSDimitry Andric       IsTopNode = true;
4115ac9a064cSDimitry Andric     } else {
4116ac9a064cSDimitry Andric       SU = pickNodeBidirectional(IsTopNode);
4117ac9a064cSDimitry Andric     }
41185ca98fd9SDimitry Andric   } while (SU->isScheduled);
41195ca98fd9SDimitry Andric 
4120ac9a064cSDimitry Andric   if (SU->isTopReady())
41215ca98fd9SDimitry Andric     Top.removeReady(SU);
4122ac9a064cSDimitry Andric   if (SU->isBottomReady())
4123ac9a064cSDimitry Andric     Bot.removeReady(SU);
41245ca98fd9SDimitry Andric 
4125eb11fae6SDimitry Andric   LLVM_DEBUG(dbgs() << "Scheduling SU(" << SU->NodeNum << ") "
4126eb11fae6SDimitry Andric                     << *SU->getInstr());
41275ca98fd9SDimitry Andric   return SU;
41285ca98fd9SDimitry Andric }
41295ca98fd9SDimitry Andric 
41305ca98fd9SDimitry Andric /// Called after ScheduleDAGMI has scheduled an instruction and updated
41315ca98fd9SDimitry Andric /// scheduled/remaining flags in the DAG nodes.
schedNode(SUnit * SU,bool IsTopNode)41325ca98fd9SDimitry Andric void PostGenericScheduler::schedNode(SUnit *SU, bool IsTopNode) {
4133ac9a064cSDimitry Andric   if (IsTopNode) {
41345ca98fd9SDimitry Andric     SU->TopReadyCycle = std::max(SU->TopReadyCycle, Top.getCurrCycle());
41355ca98fd9SDimitry Andric     Top.bumpNode(SU);
4136ac9a064cSDimitry Andric   } else {
4137ac9a064cSDimitry Andric     SU->BotReadyCycle = std::max(SU->BotReadyCycle, Bot.getCurrCycle());
4138ac9a064cSDimitry Andric     Bot.bumpNode(SU);
4139ac9a064cSDimitry Andric   }
41405ca98fd9SDimitry Andric }
41415ca98fd9SDimitry Andric 
createGenericSchedPostRA(MachineSchedContext * C)4142b915e9e0SDimitry Andric ScheduleDAGMI *llvm::createGenericSchedPostRA(MachineSchedContext *C) {
4143ac9a064cSDimitry Andric   ScheduleDAGMI *DAG =
4144ac9a064cSDimitry Andric       new ScheduleDAGMI(C, std::make_unique<PostGenericScheduler>(C),
4145b915e9e0SDimitry Andric                         /*RemoveKillFlags=*/true);
4146ac9a064cSDimitry Andric   const TargetSubtargetInfo &STI = C->MF->getSubtarget();
4147ac9a064cSDimitry Andric   // Add MacroFusion mutation if fusions are not empty.
4148ac9a064cSDimitry Andric   const auto &MacroFusions = STI.getMacroFusions();
4149ac9a064cSDimitry Andric   if (!MacroFusions.empty())
4150ac9a064cSDimitry Andric     DAG->addMutation(createMacroFusionDAGMutation(MacroFusions));
4151ac9a064cSDimitry Andric   return DAG;
41525ca98fd9SDimitry Andric }
415363faed5bSDimitry Andric 
415463faed5bSDimitry Andric //===----------------------------------------------------------------------===//
4155522600a2SDimitry Andric // ILP Scheduler. Currently for experimental analysis of heuristics.
4156522600a2SDimitry Andric //===----------------------------------------------------------------------===//
4157522600a2SDimitry Andric 
4158522600a2SDimitry Andric namespace {
415971d5a254SDimitry Andric 
4160eb11fae6SDimitry Andric /// Order nodes by the ILP metric.
4161522600a2SDimitry Andric struct ILPOrder {
416271d5a254SDimitry Andric   const SchedDFSResult *DFSResult = nullptr;
416371d5a254SDimitry Andric   const BitVector *ScheduledTrees = nullptr;
4164522600a2SDimitry Andric   bool MaximizeILP;
4165522600a2SDimitry Andric 
ILPOrder__anon233174dd0711::ILPOrder416671d5a254SDimitry Andric   ILPOrder(bool MaxILP) : MaximizeILP(MaxILP) {}
4167522600a2SDimitry Andric 
4168eb11fae6SDimitry Andric   /// Apply a less-than relation on node priority.
41694a16efa3SDimitry Andric   ///
41704a16efa3SDimitry Andric   /// (Return true if A comes after B in the Q.)
operator ()__anon233174dd0711::ILPOrder4171522600a2SDimitry Andric   bool operator()(const SUnit *A, const SUnit *B) const {
41724a16efa3SDimitry Andric     unsigned SchedTreeA = DFSResult->getSubtreeID(A);
41734a16efa3SDimitry Andric     unsigned SchedTreeB = DFSResult->getSubtreeID(B);
41744a16efa3SDimitry Andric     if (SchedTreeA != SchedTreeB) {
41754a16efa3SDimitry Andric       // Unscheduled trees have lower priority.
41764a16efa3SDimitry Andric       if (ScheduledTrees->test(SchedTreeA) != ScheduledTrees->test(SchedTreeB))
41774a16efa3SDimitry Andric         return ScheduledTrees->test(SchedTreeB);
41784a16efa3SDimitry Andric 
4179b1c73532SDimitry Andric       // Trees with shallower connections have lower priority.
41804a16efa3SDimitry Andric       if (DFSResult->getSubtreeLevel(SchedTreeA)
41814a16efa3SDimitry Andric           != DFSResult->getSubtreeLevel(SchedTreeB)) {
41824a16efa3SDimitry Andric         return DFSResult->getSubtreeLevel(SchedTreeA)
41834a16efa3SDimitry Andric           < DFSResult->getSubtreeLevel(SchedTreeB);
41844a16efa3SDimitry Andric       }
41854a16efa3SDimitry Andric     }
4186522600a2SDimitry Andric     if (MaximizeILP)
41874a16efa3SDimitry Andric       return DFSResult->getILP(A) < DFSResult->getILP(B);
4188522600a2SDimitry Andric     else
41894a16efa3SDimitry Andric       return DFSResult->getILP(A) > DFSResult->getILP(B);
4190522600a2SDimitry Andric   }
4191522600a2SDimitry Andric };
4192522600a2SDimitry Andric 
4193eb11fae6SDimitry Andric /// Schedule based on the ILP metric.
4194522600a2SDimitry Andric class ILPScheduler : public MachineSchedStrategy {
419571d5a254SDimitry Andric   ScheduleDAGMILive *DAG = nullptr;
4196522600a2SDimitry Andric   ILPOrder Cmp;
4197522600a2SDimitry Andric 
4198522600a2SDimitry Andric   std::vector<SUnit*> ReadyQ;
419971d5a254SDimitry Andric 
4200522600a2SDimitry Andric public:
ILPScheduler(bool MaximizeILP)420171d5a254SDimitry Andric   ILPScheduler(bool MaximizeILP) : Cmp(MaximizeILP) {}
4202522600a2SDimitry Andric 
initialize(ScheduleDAGMI * dag)42035ca98fd9SDimitry Andric   void initialize(ScheduleDAGMI *dag) override {
42045ca98fd9SDimitry Andric     assert(dag->hasVRegLiveness() && "ILPScheduler needs vreg liveness");
42055ca98fd9SDimitry Andric     DAG = static_cast<ScheduleDAGMILive*>(dag);
42064a16efa3SDimitry Andric     DAG->computeDFSResult();
42074a16efa3SDimitry Andric     Cmp.DFSResult = DAG->getDFSResult();
42084a16efa3SDimitry Andric     Cmp.ScheduledTrees = &DAG->getScheduledTrees();
4209522600a2SDimitry Andric     ReadyQ.clear();
4210522600a2SDimitry Andric   }
4211522600a2SDimitry Andric 
registerRoots()42125ca98fd9SDimitry Andric   void registerRoots() override {
42134a16efa3SDimitry Andric     // Restore the heap in ReadyQ with the updated DFS results.
42144a16efa3SDimitry Andric     std::make_heap(ReadyQ.begin(), ReadyQ.end(), Cmp);
4215522600a2SDimitry Andric   }
4216522600a2SDimitry Andric 
4217522600a2SDimitry Andric   /// Implement MachineSchedStrategy interface.
4218522600a2SDimitry Andric   /// -----------------------------------------
4219522600a2SDimitry Andric 
42204a16efa3SDimitry Andric   /// Callback to select the highest priority node from the ready Q.
pickNode(bool & IsTopNode)42215ca98fd9SDimitry Andric   SUnit *pickNode(bool &IsTopNode) override {
42225ca98fd9SDimitry Andric     if (ReadyQ.empty()) return nullptr;
42234a16efa3SDimitry Andric     std::pop_heap(ReadyQ.begin(), ReadyQ.end(), Cmp);
4224522600a2SDimitry Andric     SUnit *SU = ReadyQ.back();
4225522600a2SDimitry Andric     ReadyQ.pop_back();
4226522600a2SDimitry Andric     IsTopNode = false;
4227eb11fae6SDimitry Andric     LLVM_DEBUG(dbgs() << "Pick node "
4228eb11fae6SDimitry Andric                       << "SU(" << SU->NodeNum << ") "
42294a16efa3SDimitry Andric                       << " ILP: " << DAG->getDFSResult()->getILP(SU)
4230eb11fae6SDimitry Andric                       << " Tree: " << DAG->getDFSResult()->getSubtreeID(SU)
4231eb11fae6SDimitry Andric                       << " @"
42324a16efa3SDimitry Andric                       << DAG->getDFSResult()->getSubtreeLevel(
4233eb11fae6SDimitry Andric                              DAG->getDFSResult()->getSubtreeID(SU))
4234eb11fae6SDimitry Andric                       << '\n'
423559d6cff9SDimitry Andric                       << "Scheduling " << *SU->getInstr());
4236522600a2SDimitry Andric     return SU;
4237522600a2SDimitry Andric   }
4238522600a2SDimitry Andric 
4239eb11fae6SDimitry Andric   /// Scheduler callback to notify that a new subtree is scheduled.
scheduleTree(unsigned SubtreeID)42405ca98fd9SDimitry Andric   void scheduleTree(unsigned SubtreeID) override {
42414a16efa3SDimitry Andric     std::make_heap(ReadyQ.begin(), ReadyQ.end(), Cmp);
42424a16efa3SDimitry Andric   }
42434a16efa3SDimitry Andric 
42444a16efa3SDimitry Andric   /// Callback after a node is scheduled. Mark a newly scheduled tree, notify
42454a16efa3SDimitry Andric   /// DFSResults, and resort the priority Q.
schedNode(SUnit * SU,bool IsTopNode)42465ca98fd9SDimitry Andric   void schedNode(SUnit *SU, bool IsTopNode) override {
42474a16efa3SDimitry Andric     assert(!IsTopNode && "SchedDFSResult needs bottom-up");
42484a16efa3SDimitry Andric   }
4249522600a2SDimitry Andric 
releaseTopNode(SUnit *)42505ca98fd9SDimitry Andric   void releaseTopNode(SUnit *) override { /*only called for top roots*/ }
4251522600a2SDimitry Andric 
releaseBottomNode(SUnit * SU)42525ca98fd9SDimitry Andric   void releaseBottomNode(SUnit *SU) override {
4253522600a2SDimitry Andric     ReadyQ.push_back(SU);
4254522600a2SDimitry Andric     std::push_heap(ReadyQ.begin(), ReadyQ.end(), Cmp);
4255522600a2SDimitry Andric   }
4256522600a2SDimitry Andric };
425771d5a254SDimitry Andric 
425871d5a254SDimitry Andric } // end anonymous namespace
4259522600a2SDimitry Andric 
createILPMaxScheduler(MachineSchedContext * C)4260522600a2SDimitry Andric static ScheduleDAGInstrs *createILPMaxScheduler(MachineSchedContext *C) {
42611d5ae102SDimitry Andric   return new ScheduleDAGMILive(C, std::make_unique<ILPScheduler>(true));
4262522600a2SDimitry Andric }
createILPMinScheduler(MachineSchedContext * C)4263522600a2SDimitry Andric static ScheduleDAGInstrs *createILPMinScheduler(MachineSchedContext *C) {
42641d5ae102SDimitry Andric   return new ScheduleDAGMILive(C, std::make_unique<ILPScheduler>(false));
4265522600a2SDimitry Andric }
426671d5a254SDimitry Andric 
4267522600a2SDimitry Andric static MachineSchedRegistry ILPMaxRegistry(
4268522600a2SDimitry Andric   "ilpmax", "Schedule bottom-up for max ILP", createILPMaxScheduler);
4269522600a2SDimitry Andric static MachineSchedRegistry ILPMinRegistry(
4270522600a2SDimitry Andric   "ilpmin", "Schedule bottom-up for min ILP", createILPMinScheduler);
4271522600a2SDimitry Andric 
4272522600a2SDimitry Andric //===----------------------------------------------------------------------===//
427363faed5bSDimitry Andric // Machine Instruction Shuffler for Correctness Testing
427463faed5bSDimitry Andric //===----------------------------------------------------------------------===//
427563faed5bSDimitry Andric 
427663faed5bSDimitry Andric #ifndef NDEBUG
427763faed5bSDimitry Andric namespace {
427871d5a254SDimitry Andric 
427963faed5bSDimitry Andric /// Apply a less-than relation on the node order, which corresponds to the
428063faed5bSDimitry Andric /// instruction order prior to scheduling. IsReverse implements greater-than.
428163faed5bSDimitry Andric template<bool IsReverse>
428263faed5bSDimitry Andric struct SUnitOrder {
operator ()__anon233174dd0811::SUnitOrder428363faed5bSDimitry Andric   bool operator()(SUnit *A, SUnit *B) const {
428463faed5bSDimitry Andric     if (IsReverse)
428563faed5bSDimitry Andric       return A->NodeNum > B->NodeNum;
428663faed5bSDimitry Andric     else
428763faed5bSDimitry Andric       return A->NodeNum < B->NodeNum;
428863faed5bSDimitry Andric   }
428963faed5bSDimitry Andric };
429063faed5bSDimitry Andric 
429163faed5bSDimitry Andric /// Reorder instructions as much as possible.
429263faed5bSDimitry Andric class InstructionShuffler : public MachineSchedStrategy {
429363faed5bSDimitry Andric   bool IsAlternating;
429463faed5bSDimitry Andric   bool IsTopDown;
429563faed5bSDimitry Andric 
429663faed5bSDimitry Andric   // Using a less-than relation (SUnitOrder<false>) for the TopQ priority
429763faed5bSDimitry Andric   // gives nodes with a higher number higher priority causing the latest
429863faed5bSDimitry Andric   // instructions to be scheduled first.
429963faed5bSDimitry Andric   PriorityQueue<SUnit*, std::vector<SUnit*>, SUnitOrder<false>>
430063faed5bSDimitry Andric     TopQ;
4301044eb2f6SDimitry Andric 
430263faed5bSDimitry Andric   // When scheduling bottom-up, use greater-than as the queue priority.
430363faed5bSDimitry Andric   PriorityQueue<SUnit*, std::vector<SUnit*>, SUnitOrder<true>>
430463faed5bSDimitry Andric     BottomQ;
430571d5a254SDimitry Andric 
430663faed5bSDimitry Andric public:
InstructionShuffler(bool alternate,bool topdown)430763faed5bSDimitry Andric   InstructionShuffler(bool alternate, bool topdown)
430863faed5bSDimitry Andric     : IsAlternating(alternate), IsTopDown(topdown) {}
430963faed5bSDimitry Andric 
initialize(ScheduleDAGMI *)43105ca98fd9SDimitry Andric   void initialize(ScheduleDAGMI*) override {
431163faed5bSDimitry Andric     TopQ.clear();
431263faed5bSDimitry Andric     BottomQ.clear();
431363faed5bSDimitry Andric   }
431463faed5bSDimitry Andric 
431563faed5bSDimitry Andric   /// Implement MachineSchedStrategy interface.
431663faed5bSDimitry Andric   /// -----------------------------------------
431763faed5bSDimitry Andric 
pickNode(bool & IsTopNode)43185ca98fd9SDimitry Andric   SUnit *pickNode(bool &IsTopNode) override {
431963faed5bSDimitry Andric     SUnit *SU;
432063faed5bSDimitry Andric     if (IsTopDown) {
432163faed5bSDimitry Andric       do {
43225ca98fd9SDimitry Andric         if (TopQ.empty()) return nullptr;
432363faed5bSDimitry Andric         SU = TopQ.top();
432463faed5bSDimitry Andric         TopQ.pop();
432563faed5bSDimitry Andric       } while (SU->isScheduled);
432663faed5bSDimitry Andric       IsTopNode = true;
432701095a5dSDimitry Andric     } else {
432863faed5bSDimitry Andric       do {
43295ca98fd9SDimitry Andric         if (BottomQ.empty()) return nullptr;
433063faed5bSDimitry Andric         SU = BottomQ.top();
433163faed5bSDimitry Andric         BottomQ.pop();
433263faed5bSDimitry Andric       } while (SU->isScheduled);
433363faed5bSDimitry Andric       IsTopNode = false;
433463faed5bSDimitry Andric     }
433563faed5bSDimitry Andric     if (IsAlternating)
433663faed5bSDimitry Andric       IsTopDown = !IsTopDown;
433763faed5bSDimitry Andric     return SU;
433863faed5bSDimitry Andric   }
433963faed5bSDimitry Andric 
schedNode(SUnit * SU,bool IsTopNode)43405ca98fd9SDimitry Andric   void schedNode(SUnit *SU, bool IsTopNode) override {}
434158b69754SDimitry Andric 
releaseTopNode(SUnit * SU)43425ca98fd9SDimitry Andric   void releaseTopNode(SUnit *SU) override {
434363faed5bSDimitry Andric     TopQ.push(SU);
434463faed5bSDimitry Andric   }
releaseBottomNode(SUnit * SU)43455ca98fd9SDimitry Andric   void releaseBottomNode(SUnit *SU) override {
434663faed5bSDimitry Andric     BottomQ.push(SU);
434763faed5bSDimitry Andric   }
434863faed5bSDimitry Andric };
434971d5a254SDimitry Andric 
435071d5a254SDimitry Andric } // end anonymous namespace
435163faed5bSDimitry Andric 
createInstructionShuffler(MachineSchedContext * C)435263faed5bSDimitry Andric static ScheduleDAGInstrs *createInstructionShuffler(MachineSchedContext *C) {
435363faed5bSDimitry Andric   bool Alternate = !ForceTopDown && !ForceBottomUp;
435463faed5bSDimitry Andric   bool TopDown = !ForceBottomUp;
435563faed5bSDimitry Andric   assert((TopDown || !ForceTopDown) &&
435663faed5bSDimitry Andric          "-misched-topdown incompatible with -misched-bottomup");
435771d5a254SDimitry Andric   return new ScheduleDAGMILive(
43581d5ae102SDimitry Andric       C, std::make_unique<InstructionShuffler>(Alternate, TopDown));
435963faed5bSDimitry Andric }
436071d5a254SDimitry Andric 
436163faed5bSDimitry Andric static MachineSchedRegistry ShufflerRegistry(
436263faed5bSDimitry Andric   "shuffle", "Shuffle machine instructions alternating directions",
436363faed5bSDimitry Andric   createInstructionShuffler);
436463faed5bSDimitry Andric #endif // !NDEBUG
43654a16efa3SDimitry Andric 
43664a16efa3SDimitry Andric //===----------------------------------------------------------------------===//
43675ca98fd9SDimitry Andric // GraphWriter support for ScheduleDAGMILive.
43684a16efa3SDimitry Andric //===----------------------------------------------------------------------===//
43694a16efa3SDimitry Andric 
43704a16efa3SDimitry Andric #ifndef NDEBUG
43714a16efa3SDimitry Andric namespace llvm {
43724a16efa3SDimitry Andric 
43734a16efa3SDimitry Andric template<> struct GraphTraits<
43744a16efa3SDimitry Andric   ScheduleDAGMI*> : public GraphTraits<ScheduleDAG*> {};
43754a16efa3SDimitry Andric 
43764a16efa3SDimitry Andric template<>
43774a16efa3SDimitry Andric struct DOTGraphTraits<ScheduleDAGMI*> : public DefaultDOTGraphTraits {
DOTGraphTraitsllvm::DOTGraphTraits43784a16efa3SDimitry Andric   DOTGraphTraits(bool isSimple = false) : DefaultDOTGraphTraits(isSimple) {}
43794a16efa3SDimitry Andric 
getGraphNamellvm::DOTGraphTraits43804a16efa3SDimitry Andric   static std::string getGraphName(const ScheduleDAG *G) {
4381cfca06d7SDimitry Andric     return std::string(G->MF.getName());
43824a16efa3SDimitry Andric   }
43834a16efa3SDimitry Andric 
renderGraphFromBottomUpllvm::DOTGraphTraits43844a16efa3SDimitry Andric   static bool renderGraphFromBottomUp() {
43854a16efa3SDimitry Andric     return true;
43864a16efa3SDimitry Andric   }
43874a16efa3SDimitry Andric 
isNodeHiddenllvm::DOTGraphTraits4388b60736ecSDimitry Andric   static bool isNodeHidden(const SUnit *Node, const ScheduleDAG *G) {
4389dd58ef01SDimitry Andric     if (ViewMISchedCutoff == 0)
43904a16efa3SDimitry Andric       return false;
4391dd58ef01SDimitry Andric     return (Node->Preds.size() > ViewMISchedCutoff
4392dd58ef01SDimitry Andric          || Node->Succs.size() > ViewMISchedCutoff);
43934a16efa3SDimitry Andric   }
43944a16efa3SDimitry Andric 
43954a16efa3SDimitry Andric   /// If you want to override the dot attributes printed for a particular
43964a16efa3SDimitry Andric   /// edge, override this method.
getEdgeAttributesllvm::DOTGraphTraits43974a16efa3SDimitry Andric   static std::string getEdgeAttributes(const SUnit *Node,
43984a16efa3SDimitry Andric                                        SUnitIterator EI,
43994a16efa3SDimitry Andric                                        const ScheduleDAG *Graph) {
44004a16efa3SDimitry Andric     if (EI.isArtificialDep())
44014a16efa3SDimitry Andric       return "color=cyan,style=dashed";
44024a16efa3SDimitry Andric     if (EI.isCtrlDep())
44034a16efa3SDimitry Andric       return "color=blue,style=dashed";
44044a16efa3SDimitry Andric     return "";
44054a16efa3SDimitry Andric   }
44064a16efa3SDimitry Andric 
getNodeLabelllvm::DOTGraphTraits44074a16efa3SDimitry Andric   static std::string getNodeLabel(const SUnit *SU, const ScheduleDAG *G) {
44084a16efa3SDimitry Andric     std::string Str;
44094a16efa3SDimitry Andric     raw_string_ostream SS(Str);
44105ca98fd9SDimitry Andric     const ScheduleDAGMI *DAG = static_cast<const ScheduleDAGMI*>(G);
44115ca98fd9SDimitry Andric     const SchedDFSResult *DFS = DAG->hasVRegLiveness() ?
44125ca98fd9SDimitry Andric       static_cast<const ScheduleDAGMILive*>(G)->getDFSResult() : nullptr;
4413f8af5cf6SDimitry Andric     SS << "SU:" << SU->NodeNum;
4414f8af5cf6SDimitry Andric     if (DFS)
4415f8af5cf6SDimitry Andric       SS << " I:" << DFS->getNumInstrs(SU);
4416ac9a064cSDimitry Andric     return Str;
44174a16efa3SDimitry Andric   }
4418044eb2f6SDimitry Andric 
getNodeDescriptionllvm::DOTGraphTraits44194a16efa3SDimitry Andric   static std::string getNodeDescription(const SUnit *SU, const ScheduleDAG *G) {
44204a16efa3SDimitry Andric     return G->getGraphNodeLabel(SU);
44214a16efa3SDimitry Andric   }
44224a16efa3SDimitry Andric 
getNodeAttributesllvm::DOTGraphTraits44235ca98fd9SDimitry Andric   static std::string getNodeAttributes(const SUnit *N, const ScheduleDAG *G) {
44244a16efa3SDimitry Andric     std::string Str("shape=Mrecord");
44255ca98fd9SDimitry Andric     const ScheduleDAGMI *DAG = static_cast<const ScheduleDAGMI*>(G);
44265ca98fd9SDimitry Andric     const SchedDFSResult *DFS = DAG->hasVRegLiveness() ?
44275ca98fd9SDimitry Andric       static_cast<const ScheduleDAGMILive*>(G)->getDFSResult() : nullptr;
44284a16efa3SDimitry Andric     if (DFS) {
44294a16efa3SDimitry Andric       Str += ",style=filled,fillcolor=\"#";
44304a16efa3SDimitry Andric       Str += DOT::getColorString(DFS->getSubtreeID(N));
44314a16efa3SDimitry Andric       Str += '"';
44324a16efa3SDimitry Andric     }
44334a16efa3SDimitry Andric     return Str;
44344a16efa3SDimitry Andric   }
44354a16efa3SDimitry Andric };
443671d5a254SDimitry Andric 
443771d5a254SDimitry Andric } // end namespace llvm
44384a16efa3SDimitry Andric #endif // NDEBUG
44394a16efa3SDimitry Andric 
44404a16efa3SDimitry Andric /// viewGraph - Pop up a ghostview window with the reachable parts of the DAG
44414a16efa3SDimitry Andric /// rendered using 'dot'.
viewGraph(const Twine & Name,const Twine & Title)44424a16efa3SDimitry Andric void ScheduleDAGMI::viewGraph(const Twine &Name, const Twine &Title) {
44434a16efa3SDimitry Andric #ifndef NDEBUG
44444a16efa3SDimitry Andric   ViewGraph(this, Name, false, Title);
44454a16efa3SDimitry Andric #else
44464a16efa3SDimitry Andric   errs() << "ScheduleDAGMI::viewGraph is only available in debug builds on "
44474a16efa3SDimitry Andric          << "systems with Graphviz or gv!\n";
44484a16efa3SDimitry Andric #endif  // NDEBUG
44494a16efa3SDimitry Andric }
44504a16efa3SDimitry Andric 
44514a16efa3SDimitry Andric /// Out-of-line implementation with no arguments is handy for gdb.
viewGraph()44524a16efa3SDimitry Andric void ScheduleDAGMI::viewGraph() {
44534a16efa3SDimitry Andric   viewGraph(getDAGName(), "Scheduling-Units Graph for " + getDAGName());
44544a16efa3SDimitry Andric }
44557fa27ce4SDimitry Andric 
44567fa27ce4SDimitry Andric /// Sort predicate for the intervals stored in an instance of
44577fa27ce4SDimitry Andric /// ResourceSegments. Intervals are always disjoint (no intersection
44587fa27ce4SDimitry Andric /// for any pairs of intervals), therefore we can sort the totality of
44597fa27ce4SDimitry Andric /// the intervals by looking only at the left boundary.
sortIntervals(const ResourceSegments::IntervalTy & A,const ResourceSegments::IntervalTy & B)44607fa27ce4SDimitry Andric static bool sortIntervals(const ResourceSegments::IntervalTy &A,
44617fa27ce4SDimitry Andric                           const ResourceSegments::IntervalTy &B) {
44627fa27ce4SDimitry Andric   return A.first < B.first;
44637fa27ce4SDimitry Andric }
44647fa27ce4SDimitry Andric 
getFirstAvailableAt(unsigned CurrCycle,unsigned AcquireAtCycle,unsigned ReleaseAtCycle,std::function<ResourceSegments::IntervalTy (unsigned,unsigned,unsigned)> IntervalBuilder) const44657fa27ce4SDimitry Andric unsigned ResourceSegments::getFirstAvailableAt(
44664df029ccSDimitry Andric     unsigned CurrCycle, unsigned AcquireAtCycle, unsigned ReleaseAtCycle,
44677fa27ce4SDimitry Andric     std::function<ResourceSegments::IntervalTy(unsigned, unsigned, unsigned)>
44687fa27ce4SDimitry Andric         IntervalBuilder) const {
44697fa27ce4SDimitry Andric   assert(std::is_sorted(std::begin(_Intervals), std::end(_Intervals),
44707fa27ce4SDimitry Andric                         sortIntervals) &&
44717fa27ce4SDimitry Andric          "Cannot execute on an un-sorted set of intervals.");
4472ac9a064cSDimitry Andric 
4473ac9a064cSDimitry Andric   // Zero resource usage is allowed by TargetSchedule.td but we do not construct
4474ac9a064cSDimitry Andric   // a ResourceSegment interval for that situation.
4475ac9a064cSDimitry Andric   if (AcquireAtCycle == ReleaseAtCycle)
4476ac9a064cSDimitry Andric     return CurrCycle;
4477ac9a064cSDimitry Andric 
44787fa27ce4SDimitry Andric   unsigned RetCycle = CurrCycle;
44797fa27ce4SDimitry Andric   ResourceSegments::IntervalTy NewInterval =
44804df029ccSDimitry Andric       IntervalBuilder(RetCycle, AcquireAtCycle, ReleaseAtCycle);
44817fa27ce4SDimitry Andric   for (auto &Interval : _Intervals) {
44827fa27ce4SDimitry Andric     if (!intersects(NewInterval, Interval))
44837fa27ce4SDimitry Andric       continue;
44847fa27ce4SDimitry Andric 
44857fa27ce4SDimitry Andric     // Move the interval right next to the top of the one it
44867fa27ce4SDimitry Andric     // intersects.
44877fa27ce4SDimitry Andric     assert(Interval.second > NewInterval.first &&
44887fa27ce4SDimitry Andric            "Invalid intervals configuration.");
44897fa27ce4SDimitry Andric     RetCycle += (unsigned)Interval.second - (unsigned)NewInterval.first;
44904df029ccSDimitry Andric     NewInterval = IntervalBuilder(RetCycle, AcquireAtCycle, ReleaseAtCycle);
44917fa27ce4SDimitry Andric   }
44927fa27ce4SDimitry Andric   return RetCycle;
44937fa27ce4SDimitry Andric }
44947fa27ce4SDimitry Andric 
add(ResourceSegments::IntervalTy A,const unsigned CutOff)44957fa27ce4SDimitry Andric void ResourceSegments::add(ResourceSegments::IntervalTy A,
44967fa27ce4SDimitry Andric                            const unsigned CutOff) {
4497ac9a064cSDimitry Andric   assert(A.first <= A.second && "Cannot add negative resource usage");
44987fa27ce4SDimitry Andric   assert(CutOff > 0 && "0-size interval history has no use.");
4499ac9a064cSDimitry Andric   // Zero resource usage is allowed by TargetSchedule.td, in the case that the
4500ac9a064cSDimitry Andric   // instruction needed the resource to be available but does not use it.
4501ac9a064cSDimitry Andric   // However, ResourceSegment represents an interval that is closed on the left
4502ac9a064cSDimitry Andric   // and open on the right. It is impossible to represent an empty interval when
4503ac9a064cSDimitry Andric   // the left is closed. Do not add it to Intervals.
4504ac9a064cSDimitry Andric   if (A.first == A.second)
4505ac9a064cSDimitry Andric     return;
4506ac9a064cSDimitry Andric 
45077fa27ce4SDimitry Andric   assert(all_of(_Intervals,
45087fa27ce4SDimitry Andric                 [&A](const ResourceSegments::IntervalTy &Interval) -> bool {
45097fa27ce4SDimitry Andric                   return !intersects(A, Interval);
45107fa27ce4SDimitry Andric                 }) &&
45117fa27ce4SDimitry Andric          "A resource is being overwritten");
45127fa27ce4SDimitry Andric   _Intervals.push_back(A);
45137fa27ce4SDimitry Andric 
45147fa27ce4SDimitry Andric   sortAndMerge();
45157fa27ce4SDimitry Andric 
45167fa27ce4SDimitry Andric   // Do not keep the full history of the intervals, just the
45177fa27ce4SDimitry Andric   // latest #CutOff.
45187fa27ce4SDimitry Andric   while (_Intervals.size() > CutOff)
45197fa27ce4SDimitry Andric     _Intervals.pop_front();
45207fa27ce4SDimitry Andric }
45217fa27ce4SDimitry Andric 
intersects(ResourceSegments::IntervalTy A,ResourceSegments::IntervalTy B)45227fa27ce4SDimitry Andric bool ResourceSegments::intersects(ResourceSegments::IntervalTy A,
45237fa27ce4SDimitry Andric                                   ResourceSegments::IntervalTy B) {
45247fa27ce4SDimitry Andric   assert(A.first <= A.second && "Invalid interval");
45257fa27ce4SDimitry Andric   assert(B.first <= B.second && "Invalid interval");
45267fa27ce4SDimitry Andric 
45277fa27ce4SDimitry Andric   // Share one boundary.
45287fa27ce4SDimitry Andric   if ((A.first == B.first) || (A.second == B.second))
45297fa27ce4SDimitry Andric     return true;
45307fa27ce4SDimitry Andric 
45317fa27ce4SDimitry Andric   // full intersersect: [    ***     )  B
45327fa27ce4SDimitry Andric   //                        [***)       A
45337fa27ce4SDimitry Andric   if ((A.first > B.first) && (A.second < B.second))
45347fa27ce4SDimitry Andric     return true;
45357fa27ce4SDimitry Andric 
45367fa27ce4SDimitry Andric   // right intersect: [     ***)        B
45377fa27ce4SDimitry Andric   //                       [***      )  A
45387fa27ce4SDimitry Andric   if ((A.first > B.first) && (A.first < B.second) && (A.second > B.second))
45397fa27ce4SDimitry Andric     return true;
45407fa27ce4SDimitry Andric 
45417fa27ce4SDimitry Andric   // left intersect:      [***      )  B
45427fa27ce4SDimitry Andric   //                 [     ***)        A
45437fa27ce4SDimitry Andric   if ((A.first < B.first) && (B.first < A.second) && (B.second > B.first))
45447fa27ce4SDimitry Andric     return true;
45457fa27ce4SDimitry Andric 
45467fa27ce4SDimitry Andric   return false;
45477fa27ce4SDimitry Andric }
45487fa27ce4SDimitry Andric 
sortAndMerge()45497fa27ce4SDimitry Andric void ResourceSegments::sortAndMerge() {
45507fa27ce4SDimitry Andric   if (_Intervals.size() <= 1)
45517fa27ce4SDimitry Andric     return;
45527fa27ce4SDimitry Andric 
45537fa27ce4SDimitry Andric   // First sort the collection.
45547fa27ce4SDimitry Andric   _Intervals.sort(sortIntervals);
45557fa27ce4SDimitry Andric 
45567fa27ce4SDimitry Andric   // can use next because I have at least 2 elements in the list
45577fa27ce4SDimitry Andric   auto next = std::next(std::begin(_Intervals));
45587fa27ce4SDimitry Andric   auto E = std::end(_Intervals);
45597fa27ce4SDimitry Andric   for (; next != E; ++next) {
45607fa27ce4SDimitry Andric     if (std::prev(next)->second >= next->first) {
45617fa27ce4SDimitry Andric       next->first = std::prev(next)->first;
45627fa27ce4SDimitry Andric       _Intervals.erase(std::prev(next));
45637fa27ce4SDimitry Andric       continue;
45647fa27ce4SDimitry Andric     }
45657fa27ce4SDimitry Andric   }
45667fa27ce4SDimitry Andric }
4567