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