10b57cec5SDimitry Andric //===- MachineScheduler.cpp - Machine Instruction Scheduler ---------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // MachineScheduler schedules machine instructions after phi elimination. It
100b57cec5SDimitry Andric // preserves LiveIntervals so it can be invoked before register allocation.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric
140b57cec5SDimitry Andric #include "llvm/CodeGen/MachineScheduler.h"
150b57cec5SDimitry Andric #include "llvm/ADT/ArrayRef.h"
160b57cec5SDimitry Andric #include "llvm/ADT/BitVector.h"
170b57cec5SDimitry Andric #include "llvm/ADT/DenseMap.h"
180b57cec5SDimitry Andric #include "llvm/ADT/PriorityQueue.h"
190b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h"
200b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h"
21af732203SDimitry Andric #include "llvm/ADT/Statistic.h"
220b57cec5SDimitry Andric #include "llvm/ADT/iterator_range.h"
230b57cec5SDimitry Andric #include "llvm/Analysis/AliasAnalysis.h"
240b57cec5SDimitry Andric #include "llvm/CodeGen/LiveInterval.h"
250b57cec5SDimitry Andric #include "llvm/CodeGen/LiveIntervals.h"
260b57cec5SDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h"
270b57cec5SDimitry Andric #include "llvm/CodeGen/MachineDominators.h"
280b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
290b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
300b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstr.h"
310b57cec5SDimitry Andric #include "llvm/CodeGen/MachineLoopInfo.h"
320b57cec5SDimitry Andric #include "llvm/CodeGen/MachineOperand.h"
330b57cec5SDimitry Andric #include "llvm/CodeGen/MachinePassRegistry.h"
340b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
350b57cec5SDimitry Andric #include "llvm/CodeGen/Passes.h"
360b57cec5SDimitry Andric #include "llvm/CodeGen/RegisterClassInfo.h"
370b57cec5SDimitry Andric #include "llvm/CodeGen/RegisterPressure.h"
380b57cec5SDimitry Andric #include "llvm/CodeGen/ScheduleDAG.h"
390b57cec5SDimitry Andric #include "llvm/CodeGen/ScheduleDAGInstrs.h"
400b57cec5SDimitry Andric #include "llvm/CodeGen/ScheduleDAGMutation.h"
410b57cec5SDimitry Andric #include "llvm/CodeGen/ScheduleDFS.h"
420b57cec5SDimitry Andric #include "llvm/CodeGen/ScheduleHazardRecognizer.h"
430b57cec5SDimitry Andric #include "llvm/CodeGen/SlotIndexes.h"
440b57cec5SDimitry Andric #include "llvm/CodeGen/TargetFrameLowering.h"
450b57cec5SDimitry Andric #include "llvm/CodeGen/TargetInstrInfo.h"
460b57cec5SDimitry Andric #include "llvm/CodeGen/TargetLowering.h"
470b57cec5SDimitry Andric #include "llvm/CodeGen/TargetPassConfig.h"
480b57cec5SDimitry Andric #include "llvm/CodeGen/TargetRegisterInfo.h"
490b57cec5SDimitry Andric #include "llvm/CodeGen/TargetSchedule.h"
500b57cec5SDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h"
510b57cec5SDimitry Andric #include "llvm/Config/llvm-config.h"
52480093f4SDimitry Andric #include "llvm/InitializePasses.h"
530b57cec5SDimitry Andric #include "llvm/MC/LaneBitmask.h"
540b57cec5SDimitry Andric #include "llvm/Pass.h"
550b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h"
560b57cec5SDimitry Andric #include "llvm/Support/Compiler.h"
570b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
580b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
590b57cec5SDimitry Andric #include "llvm/Support/GraphWriter.h"
600b57cec5SDimitry Andric #include "llvm/Support/MachineValueType.h"
610b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
620b57cec5SDimitry Andric #include <algorithm>
630b57cec5SDimitry Andric #include <cassert>
640b57cec5SDimitry Andric #include <cstdint>
650b57cec5SDimitry Andric #include <iterator>
660b57cec5SDimitry Andric #include <limits>
670b57cec5SDimitry Andric #include <memory>
680b57cec5SDimitry Andric #include <string>
690b57cec5SDimitry Andric #include <tuple>
700b57cec5SDimitry Andric #include <utility>
710b57cec5SDimitry Andric #include <vector>
720b57cec5SDimitry Andric
730b57cec5SDimitry Andric using namespace llvm;
740b57cec5SDimitry Andric
750b57cec5SDimitry Andric #define DEBUG_TYPE "machine-scheduler"
760b57cec5SDimitry Andric
77af732203SDimitry Andric STATISTIC(NumClustered, "Number of load/store pairs clustered");
78af732203SDimitry Andric
790b57cec5SDimitry Andric namespace llvm {
800b57cec5SDimitry Andric
810b57cec5SDimitry Andric cl::opt<bool> ForceTopDown("misched-topdown", cl::Hidden,
820b57cec5SDimitry Andric cl::desc("Force top-down list scheduling"));
830b57cec5SDimitry Andric cl::opt<bool> ForceBottomUp("misched-bottomup", cl::Hidden,
840b57cec5SDimitry Andric cl::desc("Force bottom-up list scheduling"));
850b57cec5SDimitry Andric cl::opt<bool>
860b57cec5SDimitry Andric DumpCriticalPathLength("misched-dcpl", cl::Hidden,
870b57cec5SDimitry Andric cl::desc("Print critical path length to stdout"));
880b57cec5SDimitry Andric
898bcb0991SDimitry Andric cl::opt<bool> VerifyScheduling(
908bcb0991SDimitry Andric "verify-misched", cl::Hidden,
918bcb0991SDimitry Andric cl::desc("Verify machine instrs before and after machine scheduling"));
928bcb0991SDimitry Andric
930b57cec5SDimitry Andric } // end namespace llvm
940b57cec5SDimitry Andric
950b57cec5SDimitry Andric #ifndef NDEBUG
960b57cec5SDimitry Andric static cl::opt<bool> ViewMISchedDAGs("view-misched-dags", cl::Hidden,
970b57cec5SDimitry Andric cl::desc("Pop up a window to show MISched dags after they are processed"));
980b57cec5SDimitry Andric
990b57cec5SDimitry Andric /// In some situations a few uninteresting nodes depend on nearly all other
1000b57cec5SDimitry Andric /// nodes in the graph, provide a cutoff to hide them.
1010b57cec5SDimitry Andric static cl::opt<unsigned> ViewMISchedCutoff("view-misched-cutoff", cl::Hidden,
1020b57cec5SDimitry Andric cl::desc("Hide nodes with more predecessor/successor than cutoff"));
1030b57cec5SDimitry Andric
1040b57cec5SDimitry Andric static cl::opt<unsigned> MISchedCutoff("misched-cutoff", cl::Hidden,
1050b57cec5SDimitry Andric cl::desc("Stop scheduling after N instructions"), cl::init(~0U));
1060b57cec5SDimitry Andric
1070b57cec5SDimitry Andric static cl::opt<std::string> SchedOnlyFunc("misched-only-func", cl::Hidden,
1080b57cec5SDimitry Andric cl::desc("Only schedule this function"));
1090b57cec5SDimitry Andric static cl::opt<unsigned> SchedOnlyBlock("misched-only-block", cl::Hidden,
1100b57cec5SDimitry Andric cl::desc("Only schedule this MBB#"));
1110b57cec5SDimitry Andric static cl::opt<bool> PrintDAGs("misched-print-dags", cl::Hidden,
1120b57cec5SDimitry Andric cl::desc("Print schedule DAGs"));
1130b57cec5SDimitry Andric #else
1140b57cec5SDimitry Andric static const bool ViewMISchedDAGs = false;
1150b57cec5SDimitry Andric static const bool PrintDAGs = false;
1160b57cec5SDimitry Andric #endif // NDEBUG
1170b57cec5SDimitry Andric
1180b57cec5SDimitry Andric /// Avoid quadratic complexity in unusually large basic blocks by limiting the
1190b57cec5SDimitry Andric /// size of the ready lists.
1200b57cec5SDimitry Andric static cl::opt<unsigned> ReadyListLimit("misched-limit", cl::Hidden,
1210b57cec5SDimitry Andric cl::desc("Limit ready list to N instructions"), cl::init(256));
1220b57cec5SDimitry Andric
1230b57cec5SDimitry Andric static cl::opt<bool> EnableRegPressure("misched-regpressure", cl::Hidden,
1240b57cec5SDimitry Andric cl::desc("Enable register pressure scheduling."), cl::init(true));
1250b57cec5SDimitry Andric
1260b57cec5SDimitry Andric static cl::opt<bool> EnableCyclicPath("misched-cyclicpath", cl::Hidden,
1270b57cec5SDimitry Andric cl::desc("Enable cyclic critical path analysis."), cl::init(true));
1280b57cec5SDimitry Andric
1290b57cec5SDimitry Andric static cl::opt<bool> EnableMemOpCluster("misched-cluster", cl::Hidden,
1300b57cec5SDimitry Andric cl::desc("Enable memop clustering."),
1310b57cec5SDimitry Andric cl::init(true));
132af732203SDimitry Andric static cl::opt<bool>
133af732203SDimitry Andric ForceFastCluster("force-fast-cluster", cl::Hidden,
134af732203SDimitry Andric cl::desc("Switch to fast cluster algorithm with the lost "
135af732203SDimitry Andric "of some fusion opportunities"),
136af732203SDimitry Andric cl::init(false));
137af732203SDimitry Andric static cl::opt<unsigned>
138af732203SDimitry Andric FastClusterThreshold("fast-cluster-threshold", cl::Hidden,
139af732203SDimitry Andric cl::desc("The threshold for fast cluster"),
140af732203SDimitry Andric cl::init(1000));
1410b57cec5SDimitry Andric
1420b57cec5SDimitry Andric // DAG subtrees must have at least this many nodes.
1430b57cec5SDimitry Andric static const unsigned MinSubtreeSize = 8;
1440b57cec5SDimitry Andric
1450b57cec5SDimitry Andric // Pin the vtables to this file.
anchor()1460b57cec5SDimitry Andric void MachineSchedStrategy::anchor() {}
1470b57cec5SDimitry Andric
anchor()1480b57cec5SDimitry Andric void ScheduleDAGMutation::anchor() {}
1490b57cec5SDimitry Andric
1500b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
1510b57cec5SDimitry Andric // Machine Instruction Scheduling Pass and Registry
1520b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
1530b57cec5SDimitry Andric
MachineSchedContext()1540b57cec5SDimitry Andric MachineSchedContext::MachineSchedContext() {
1550b57cec5SDimitry Andric RegClassInfo = new RegisterClassInfo();
1560b57cec5SDimitry Andric }
1570b57cec5SDimitry Andric
~MachineSchedContext()1580b57cec5SDimitry Andric MachineSchedContext::~MachineSchedContext() {
1590b57cec5SDimitry Andric delete RegClassInfo;
1600b57cec5SDimitry Andric }
1610b57cec5SDimitry Andric
1620b57cec5SDimitry Andric namespace {
1630b57cec5SDimitry Andric
1640b57cec5SDimitry Andric /// Base class for a machine scheduler class that can run at any point.
1650b57cec5SDimitry Andric class MachineSchedulerBase : public MachineSchedContext,
1660b57cec5SDimitry Andric public MachineFunctionPass {
1670b57cec5SDimitry Andric public:
MachineSchedulerBase(char & ID)1680b57cec5SDimitry Andric MachineSchedulerBase(char &ID): MachineFunctionPass(ID) {}
1690b57cec5SDimitry Andric
1700b57cec5SDimitry Andric void print(raw_ostream &O, const Module* = nullptr) const override;
1710b57cec5SDimitry Andric
1720b57cec5SDimitry Andric protected:
1730b57cec5SDimitry Andric void scheduleRegions(ScheduleDAGInstrs &Scheduler, bool FixKillFlags);
1740b57cec5SDimitry Andric };
1750b57cec5SDimitry Andric
1760b57cec5SDimitry Andric /// MachineScheduler runs after coalescing and before register allocation.
1770b57cec5SDimitry Andric class MachineScheduler : public MachineSchedulerBase {
1780b57cec5SDimitry Andric public:
1790b57cec5SDimitry Andric MachineScheduler();
1800b57cec5SDimitry Andric
1810b57cec5SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override;
1820b57cec5SDimitry Andric
1830b57cec5SDimitry Andric bool runOnMachineFunction(MachineFunction&) override;
1840b57cec5SDimitry Andric
1850b57cec5SDimitry Andric static char ID; // Class identification, replacement for typeinfo
1860b57cec5SDimitry Andric
1870b57cec5SDimitry Andric protected:
1880b57cec5SDimitry Andric ScheduleDAGInstrs *createMachineScheduler();
1890b57cec5SDimitry Andric };
1900b57cec5SDimitry Andric
1910b57cec5SDimitry Andric /// PostMachineScheduler runs after shortly before code emission.
1920b57cec5SDimitry Andric class PostMachineScheduler : public MachineSchedulerBase {
1930b57cec5SDimitry Andric public:
1940b57cec5SDimitry Andric PostMachineScheduler();
1950b57cec5SDimitry Andric
1960b57cec5SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override;
1970b57cec5SDimitry Andric
1980b57cec5SDimitry Andric bool runOnMachineFunction(MachineFunction&) override;
1990b57cec5SDimitry Andric
2000b57cec5SDimitry Andric static char ID; // Class identification, replacement for typeinfo
2010b57cec5SDimitry Andric
2020b57cec5SDimitry Andric protected:
2030b57cec5SDimitry Andric ScheduleDAGInstrs *createPostMachineScheduler();
2040b57cec5SDimitry Andric };
2050b57cec5SDimitry Andric
2060b57cec5SDimitry Andric } // end anonymous namespace
2070b57cec5SDimitry Andric
2080b57cec5SDimitry Andric char MachineScheduler::ID = 0;
2090b57cec5SDimitry Andric
2100b57cec5SDimitry Andric char &llvm::MachineSchedulerID = MachineScheduler::ID;
2110b57cec5SDimitry Andric
2120b57cec5SDimitry Andric INITIALIZE_PASS_BEGIN(MachineScheduler, DEBUG_TYPE,
2130b57cec5SDimitry Andric "Machine Instruction Scheduler", false, false)
INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass)2140b57cec5SDimitry Andric INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass)
2158bcb0991SDimitry Andric INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree)
2160b57cec5SDimitry Andric INITIALIZE_PASS_DEPENDENCY(MachineLoopInfo)
2170b57cec5SDimitry Andric INITIALIZE_PASS_DEPENDENCY(SlotIndexes)
2180b57cec5SDimitry Andric INITIALIZE_PASS_DEPENDENCY(LiveIntervals)
2190b57cec5SDimitry Andric INITIALIZE_PASS_END(MachineScheduler, DEBUG_TYPE,
2200b57cec5SDimitry Andric "Machine Instruction Scheduler", false, false)
2210b57cec5SDimitry Andric
2220b57cec5SDimitry Andric MachineScheduler::MachineScheduler() : MachineSchedulerBase(ID) {
2230b57cec5SDimitry Andric initializeMachineSchedulerPass(*PassRegistry::getPassRegistry());
2240b57cec5SDimitry Andric }
2250b57cec5SDimitry Andric
getAnalysisUsage(AnalysisUsage & AU) const2260b57cec5SDimitry Andric void MachineScheduler::getAnalysisUsage(AnalysisUsage &AU) const {
2270b57cec5SDimitry Andric AU.setPreservesCFG();
2288bcb0991SDimitry Andric AU.addRequired<MachineDominatorTree>();
2290b57cec5SDimitry Andric AU.addRequired<MachineLoopInfo>();
2300b57cec5SDimitry Andric AU.addRequired<AAResultsWrapperPass>();
2310b57cec5SDimitry Andric AU.addRequired<TargetPassConfig>();
2320b57cec5SDimitry Andric AU.addRequired<SlotIndexes>();
2330b57cec5SDimitry Andric AU.addPreserved<SlotIndexes>();
2340b57cec5SDimitry Andric AU.addRequired<LiveIntervals>();
2350b57cec5SDimitry Andric AU.addPreserved<LiveIntervals>();
2360b57cec5SDimitry Andric MachineFunctionPass::getAnalysisUsage(AU);
2370b57cec5SDimitry Andric }
2380b57cec5SDimitry Andric
2390b57cec5SDimitry Andric char PostMachineScheduler::ID = 0;
2400b57cec5SDimitry Andric
2410b57cec5SDimitry Andric char &llvm::PostMachineSchedulerID = PostMachineScheduler::ID;
2420b57cec5SDimitry Andric
243af732203SDimitry Andric INITIALIZE_PASS_BEGIN(PostMachineScheduler, "postmisched",
244af732203SDimitry Andric "PostRA Machine Instruction Scheduler", false, false)
INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree)245af732203SDimitry Andric INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree)
246af732203SDimitry Andric INITIALIZE_PASS_DEPENDENCY(MachineLoopInfo)
247af732203SDimitry Andric INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass)
248af732203SDimitry Andric INITIALIZE_PASS_END(PostMachineScheduler, "postmisched",
2490b57cec5SDimitry Andric "PostRA Machine Instruction Scheduler", false, false)
2500b57cec5SDimitry Andric
2510b57cec5SDimitry Andric PostMachineScheduler::PostMachineScheduler() : MachineSchedulerBase(ID) {
2520b57cec5SDimitry Andric initializePostMachineSchedulerPass(*PassRegistry::getPassRegistry());
2530b57cec5SDimitry Andric }
2540b57cec5SDimitry Andric
getAnalysisUsage(AnalysisUsage & AU) const2550b57cec5SDimitry Andric void PostMachineScheduler::getAnalysisUsage(AnalysisUsage &AU) const {
2560b57cec5SDimitry Andric AU.setPreservesCFG();
2578bcb0991SDimitry Andric AU.addRequired<MachineDominatorTree>();
2580b57cec5SDimitry Andric AU.addRequired<MachineLoopInfo>();
259480093f4SDimitry Andric AU.addRequired<AAResultsWrapperPass>();
2600b57cec5SDimitry Andric AU.addRequired<TargetPassConfig>();
2610b57cec5SDimitry Andric MachineFunctionPass::getAnalysisUsage(AU);
2620b57cec5SDimitry Andric }
2630b57cec5SDimitry Andric
2640b57cec5SDimitry Andric MachinePassRegistry<MachineSchedRegistry::ScheduleDAGCtor>
2650b57cec5SDimitry Andric MachineSchedRegistry::Registry;
2660b57cec5SDimitry Andric
2670b57cec5SDimitry Andric /// A dummy default scheduler factory indicates whether the scheduler
2680b57cec5SDimitry Andric /// is overridden on the command line.
useDefaultMachineSched(MachineSchedContext * C)2690b57cec5SDimitry Andric static ScheduleDAGInstrs *useDefaultMachineSched(MachineSchedContext *C) {
2700b57cec5SDimitry Andric return nullptr;
2710b57cec5SDimitry Andric }
2720b57cec5SDimitry Andric
2730b57cec5SDimitry Andric /// MachineSchedOpt allows command line selection of the scheduler.
2740b57cec5SDimitry Andric static cl::opt<MachineSchedRegistry::ScheduleDAGCtor, false,
2750b57cec5SDimitry Andric RegisterPassParser<MachineSchedRegistry>>
2760b57cec5SDimitry Andric MachineSchedOpt("misched",
2770b57cec5SDimitry Andric cl::init(&useDefaultMachineSched), cl::Hidden,
2780b57cec5SDimitry Andric cl::desc("Machine instruction scheduler to use"));
2790b57cec5SDimitry Andric
2800b57cec5SDimitry Andric static MachineSchedRegistry
2810b57cec5SDimitry Andric DefaultSchedRegistry("default", "Use the target's default scheduler choice.",
2820b57cec5SDimitry Andric useDefaultMachineSched);
2830b57cec5SDimitry Andric
2840b57cec5SDimitry Andric static cl::opt<bool> EnableMachineSched(
2850b57cec5SDimitry Andric "enable-misched",
2860b57cec5SDimitry Andric cl::desc("Enable the machine instruction scheduling pass."), cl::init(true),
2870b57cec5SDimitry Andric cl::Hidden);
2880b57cec5SDimitry Andric
2890b57cec5SDimitry Andric static cl::opt<bool> EnablePostRAMachineSched(
2900b57cec5SDimitry Andric "enable-post-misched",
2910b57cec5SDimitry Andric cl::desc("Enable the post-ra machine instruction scheduling pass."),
2920b57cec5SDimitry Andric cl::init(true), cl::Hidden);
2930b57cec5SDimitry Andric
2940b57cec5SDimitry Andric /// Decrement this iterator until reaching the top or a non-debug instr.
2950b57cec5SDimitry Andric static MachineBasicBlock::const_iterator
priorNonDebug(MachineBasicBlock::const_iterator I,MachineBasicBlock::const_iterator Beg)2960b57cec5SDimitry Andric priorNonDebug(MachineBasicBlock::const_iterator I,
2970b57cec5SDimitry Andric MachineBasicBlock::const_iterator Beg) {
2980b57cec5SDimitry Andric assert(I != Beg && "reached the top of the region, cannot decrement");
2990b57cec5SDimitry Andric while (--I != Beg) {
300*5f7ddb14SDimitry Andric if (!I->isDebugOrPseudoInstr())
3010b57cec5SDimitry Andric break;
3020b57cec5SDimitry Andric }
3030b57cec5SDimitry Andric return I;
3040b57cec5SDimitry Andric }
3050b57cec5SDimitry Andric
3060b57cec5SDimitry Andric /// Non-const version.
3070b57cec5SDimitry Andric static MachineBasicBlock::iterator
priorNonDebug(MachineBasicBlock::iterator I,MachineBasicBlock::const_iterator Beg)3080b57cec5SDimitry Andric priorNonDebug(MachineBasicBlock::iterator I,
3090b57cec5SDimitry Andric MachineBasicBlock::const_iterator Beg) {
3100b57cec5SDimitry Andric return priorNonDebug(MachineBasicBlock::const_iterator(I), Beg)
3110b57cec5SDimitry Andric .getNonConstIterator();
3120b57cec5SDimitry Andric }
3130b57cec5SDimitry Andric
3140b57cec5SDimitry Andric /// If this iterator is a debug value, increment until reaching the End or a
3150b57cec5SDimitry Andric /// non-debug instruction.
3160b57cec5SDimitry Andric static MachineBasicBlock::const_iterator
nextIfDebug(MachineBasicBlock::const_iterator I,MachineBasicBlock::const_iterator End)3170b57cec5SDimitry Andric nextIfDebug(MachineBasicBlock::const_iterator I,
3180b57cec5SDimitry Andric MachineBasicBlock::const_iterator End) {
3190b57cec5SDimitry Andric for(; I != End; ++I) {
320*5f7ddb14SDimitry Andric if (!I->isDebugOrPseudoInstr())
3210b57cec5SDimitry Andric break;
3220b57cec5SDimitry Andric }
3230b57cec5SDimitry Andric return I;
3240b57cec5SDimitry Andric }
3250b57cec5SDimitry Andric
3260b57cec5SDimitry Andric /// Non-const version.
3270b57cec5SDimitry Andric static MachineBasicBlock::iterator
nextIfDebug(MachineBasicBlock::iterator I,MachineBasicBlock::const_iterator End)3280b57cec5SDimitry Andric nextIfDebug(MachineBasicBlock::iterator I,
3290b57cec5SDimitry Andric MachineBasicBlock::const_iterator End) {
3300b57cec5SDimitry Andric return nextIfDebug(MachineBasicBlock::const_iterator(I), End)
3310b57cec5SDimitry Andric .getNonConstIterator();
3320b57cec5SDimitry Andric }
3330b57cec5SDimitry Andric
3340b57cec5SDimitry Andric /// Instantiate a ScheduleDAGInstrs that will be owned by the caller.
createMachineScheduler()3350b57cec5SDimitry Andric ScheduleDAGInstrs *MachineScheduler::createMachineScheduler() {
3360b57cec5SDimitry Andric // Select the scheduler, or set the default.
3370b57cec5SDimitry Andric MachineSchedRegistry::ScheduleDAGCtor Ctor = MachineSchedOpt;
3380b57cec5SDimitry Andric if (Ctor != useDefaultMachineSched)
3390b57cec5SDimitry Andric return Ctor(this);
3400b57cec5SDimitry Andric
3410b57cec5SDimitry Andric // Get the default scheduler set by the target for this function.
3420b57cec5SDimitry Andric ScheduleDAGInstrs *Scheduler = PassConfig->createMachineScheduler(this);
3430b57cec5SDimitry Andric if (Scheduler)
3440b57cec5SDimitry Andric return Scheduler;
3450b57cec5SDimitry Andric
3460b57cec5SDimitry Andric // Default to GenericScheduler.
3470b57cec5SDimitry Andric return createGenericSchedLive(this);
3480b57cec5SDimitry Andric }
3490b57cec5SDimitry Andric
3500b57cec5SDimitry Andric /// Instantiate a ScheduleDAGInstrs for PostRA scheduling that will be owned by
3510b57cec5SDimitry Andric /// the caller. We don't have a command line option to override the postRA
3520b57cec5SDimitry Andric /// scheduler. The Target must configure it.
createPostMachineScheduler()3530b57cec5SDimitry Andric ScheduleDAGInstrs *PostMachineScheduler::createPostMachineScheduler() {
3540b57cec5SDimitry Andric // Get the postRA scheduler set by the target for this function.
3550b57cec5SDimitry Andric ScheduleDAGInstrs *Scheduler = PassConfig->createPostMachineScheduler(this);
3560b57cec5SDimitry Andric if (Scheduler)
3570b57cec5SDimitry Andric return Scheduler;
3580b57cec5SDimitry Andric
3590b57cec5SDimitry Andric // Default to GenericScheduler.
3600b57cec5SDimitry Andric return createGenericSchedPostRA(this);
3610b57cec5SDimitry Andric }
3620b57cec5SDimitry Andric
3630b57cec5SDimitry Andric /// Top-level MachineScheduler pass driver.
3640b57cec5SDimitry Andric ///
3650b57cec5SDimitry Andric /// Visit blocks in function order. Divide each block into scheduling regions
3660b57cec5SDimitry Andric /// and visit them bottom-up. Visiting regions bottom-up is not required, but is
3670b57cec5SDimitry Andric /// consistent with the DAG builder, which traverses the interior of the
3680b57cec5SDimitry Andric /// scheduling regions bottom-up.
3690b57cec5SDimitry Andric ///
3700b57cec5SDimitry Andric /// This design avoids exposing scheduling boundaries to the DAG builder,
3710b57cec5SDimitry Andric /// simplifying the DAG builder's support for "special" target instructions.
3720b57cec5SDimitry Andric /// At the same time the design allows target schedulers to operate across
3730b57cec5SDimitry Andric /// scheduling boundaries, for example to bundle the boundary instructions
3740b57cec5SDimitry Andric /// without reordering them. This creates complexity, because the target
3750b57cec5SDimitry Andric /// scheduler must update the RegionBegin and RegionEnd positions cached by
3760b57cec5SDimitry Andric /// ScheduleDAGInstrs whenever adding or removing instructions. A much simpler
3770b57cec5SDimitry Andric /// design would be to split blocks at scheduling boundaries, but LLVM has a
3780b57cec5SDimitry Andric /// general bias against block splitting purely for implementation simplicity.
runOnMachineFunction(MachineFunction & mf)3790b57cec5SDimitry Andric bool MachineScheduler::runOnMachineFunction(MachineFunction &mf) {
3800b57cec5SDimitry Andric if (skipFunction(mf.getFunction()))
3810b57cec5SDimitry Andric return false;
3820b57cec5SDimitry Andric
3830b57cec5SDimitry Andric if (EnableMachineSched.getNumOccurrences()) {
3840b57cec5SDimitry Andric if (!EnableMachineSched)
3850b57cec5SDimitry Andric return false;
3860b57cec5SDimitry Andric } else if (!mf.getSubtarget().enableMachineScheduler())
3870b57cec5SDimitry Andric return false;
3880b57cec5SDimitry Andric
3890b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Before MISched:\n"; mf.print(dbgs()));
3900b57cec5SDimitry Andric
3910b57cec5SDimitry Andric // Initialize the context of the pass.
3920b57cec5SDimitry Andric MF = &mf;
3930b57cec5SDimitry Andric MLI = &getAnalysis<MachineLoopInfo>();
3940b57cec5SDimitry Andric MDT = &getAnalysis<MachineDominatorTree>();
3950b57cec5SDimitry Andric PassConfig = &getAnalysis<TargetPassConfig>();
3960b57cec5SDimitry Andric AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();
3970b57cec5SDimitry Andric
3980b57cec5SDimitry Andric LIS = &getAnalysis<LiveIntervals>();
3990b57cec5SDimitry Andric
4000b57cec5SDimitry Andric if (VerifyScheduling) {
4010b57cec5SDimitry Andric LLVM_DEBUG(LIS->dump());
4020b57cec5SDimitry Andric MF->verify(this, "Before machine scheduling.");
4030b57cec5SDimitry Andric }
4040b57cec5SDimitry Andric RegClassInfo->runOnMachineFunction(*MF);
4050b57cec5SDimitry Andric
4060b57cec5SDimitry Andric // Instantiate the selected scheduler for this target, function, and
4070b57cec5SDimitry Andric // optimization level.
4080b57cec5SDimitry Andric std::unique_ptr<ScheduleDAGInstrs> Scheduler(createMachineScheduler());
4090b57cec5SDimitry Andric scheduleRegions(*Scheduler, false);
4100b57cec5SDimitry Andric
4110b57cec5SDimitry Andric LLVM_DEBUG(LIS->dump());
4120b57cec5SDimitry Andric if (VerifyScheduling)
4130b57cec5SDimitry Andric MF->verify(this, "After machine scheduling.");
4140b57cec5SDimitry Andric return true;
4150b57cec5SDimitry Andric }
4160b57cec5SDimitry Andric
runOnMachineFunction(MachineFunction & mf)4170b57cec5SDimitry Andric bool PostMachineScheduler::runOnMachineFunction(MachineFunction &mf) {
4180b57cec5SDimitry Andric if (skipFunction(mf.getFunction()))
4190b57cec5SDimitry Andric return false;
4200b57cec5SDimitry Andric
4210b57cec5SDimitry Andric if (EnablePostRAMachineSched.getNumOccurrences()) {
4220b57cec5SDimitry Andric if (!EnablePostRAMachineSched)
4230b57cec5SDimitry Andric return false;
424480093f4SDimitry Andric } else if (!mf.getSubtarget().enablePostRAMachineScheduler()) {
4250b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Subtarget disables post-MI-sched.\n");
4260b57cec5SDimitry Andric return false;
4270b57cec5SDimitry Andric }
4280b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Before post-MI-sched:\n"; mf.print(dbgs()));
4290b57cec5SDimitry Andric
4300b57cec5SDimitry Andric // Initialize the context of the pass.
4310b57cec5SDimitry Andric MF = &mf;
4320b57cec5SDimitry Andric MLI = &getAnalysis<MachineLoopInfo>();
4330b57cec5SDimitry Andric PassConfig = &getAnalysis<TargetPassConfig>();
434480093f4SDimitry Andric AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();
4350b57cec5SDimitry Andric
4360b57cec5SDimitry Andric if (VerifyScheduling)
4370b57cec5SDimitry Andric MF->verify(this, "Before post machine scheduling.");
4380b57cec5SDimitry Andric
4390b57cec5SDimitry Andric // Instantiate the selected scheduler for this target, function, and
4400b57cec5SDimitry Andric // optimization level.
4410b57cec5SDimitry Andric std::unique_ptr<ScheduleDAGInstrs> Scheduler(createPostMachineScheduler());
4420b57cec5SDimitry Andric scheduleRegions(*Scheduler, true);
4430b57cec5SDimitry Andric
4440b57cec5SDimitry Andric if (VerifyScheduling)
4450b57cec5SDimitry Andric MF->verify(this, "After post machine scheduling.");
4460b57cec5SDimitry Andric return true;
4470b57cec5SDimitry Andric }
4480b57cec5SDimitry Andric
4490b57cec5SDimitry Andric /// Return true of the given instruction should not be included in a scheduling
4500b57cec5SDimitry Andric /// region.
4510b57cec5SDimitry Andric ///
4520b57cec5SDimitry Andric /// MachineScheduler does not currently support scheduling across calls. To
4530b57cec5SDimitry Andric /// handle calls, the DAG builder needs to be modified to create register
4540b57cec5SDimitry Andric /// anti/output dependencies on the registers clobbered by the call's regmask
4550b57cec5SDimitry Andric /// operand. In PreRA scheduling, the stack pointer adjustment already prevents
4560b57cec5SDimitry Andric /// scheduling across calls. In PostRA scheduling, we need the isCall to enforce
4570b57cec5SDimitry Andric /// the boundary, but there would be no benefit to postRA scheduling across
4580b57cec5SDimitry Andric /// calls this late anyway.
isSchedBoundary(MachineBasicBlock::iterator MI,MachineBasicBlock * MBB,MachineFunction * MF,const TargetInstrInfo * TII)4590b57cec5SDimitry Andric static bool isSchedBoundary(MachineBasicBlock::iterator MI,
4600b57cec5SDimitry Andric MachineBasicBlock *MBB,
4610b57cec5SDimitry Andric MachineFunction *MF,
4620b57cec5SDimitry Andric const TargetInstrInfo *TII) {
4630b57cec5SDimitry Andric return MI->isCall() || TII->isSchedulingBoundary(*MI, MBB, *MF);
4640b57cec5SDimitry Andric }
4650b57cec5SDimitry Andric
4660b57cec5SDimitry Andric /// A region of an MBB for scheduling.
4670b57cec5SDimitry Andric namespace {
4680b57cec5SDimitry Andric struct SchedRegion {
4690b57cec5SDimitry Andric /// RegionBegin is the first instruction in the scheduling region, and
4700b57cec5SDimitry Andric /// RegionEnd is either MBB->end() or the scheduling boundary after the
4710b57cec5SDimitry Andric /// last instruction in the scheduling region. These iterators cannot refer
4720b57cec5SDimitry Andric /// to instructions outside of the identified scheduling region because
4730b57cec5SDimitry Andric /// those may be reordered before scheduling this region.
4740b57cec5SDimitry Andric MachineBasicBlock::iterator RegionBegin;
4750b57cec5SDimitry Andric MachineBasicBlock::iterator RegionEnd;
4760b57cec5SDimitry Andric unsigned NumRegionInstrs;
4770b57cec5SDimitry Andric
SchedRegion__anonde6daefc0211::SchedRegion4780b57cec5SDimitry Andric SchedRegion(MachineBasicBlock::iterator B, MachineBasicBlock::iterator E,
4790b57cec5SDimitry Andric unsigned N) :
4800b57cec5SDimitry Andric RegionBegin(B), RegionEnd(E), NumRegionInstrs(N) {}
4810b57cec5SDimitry Andric };
4820b57cec5SDimitry Andric } // end anonymous namespace
4830b57cec5SDimitry Andric
4840b57cec5SDimitry Andric using MBBRegionsVector = SmallVector<SchedRegion, 16>;
4850b57cec5SDimitry Andric
4860b57cec5SDimitry Andric static void
getSchedRegions(MachineBasicBlock * MBB,MBBRegionsVector & Regions,bool RegionsTopDown)4870b57cec5SDimitry Andric getSchedRegions(MachineBasicBlock *MBB,
4880b57cec5SDimitry Andric MBBRegionsVector &Regions,
4890b57cec5SDimitry Andric bool RegionsTopDown) {
4900b57cec5SDimitry Andric MachineFunction *MF = MBB->getParent();
4910b57cec5SDimitry Andric const TargetInstrInfo *TII = MF->getSubtarget().getInstrInfo();
4920b57cec5SDimitry Andric
4930b57cec5SDimitry Andric MachineBasicBlock::iterator I = nullptr;
4940b57cec5SDimitry Andric for(MachineBasicBlock::iterator RegionEnd = MBB->end();
4950b57cec5SDimitry Andric RegionEnd != MBB->begin(); RegionEnd = I) {
4960b57cec5SDimitry Andric
4970b57cec5SDimitry Andric // Avoid decrementing RegionEnd for blocks with no terminator.
4980b57cec5SDimitry Andric if (RegionEnd != MBB->end() ||
4990b57cec5SDimitry Andric isSchedBoundary(&*std::prev(RegionEnd), &*MBB, MF, TII)) {
5000b57cec5SDimitry Andric --RegionEnd;
5010b57cec5SDimitry Andric }
5020b57cec5SDimitry Andric
5030b57cec5SDimitry Andric // The next region starts above the previous region. Look backward in the
5040b57cec5SDimitry Andric // instruction stream until we find the nearest boundary.
5050b57cec5SDimitry Andric unsigned NumRegionInstrs = 0;
5060b57cec5SDimitry Andric I = RegionEnd;
5070b57cec5SDimitry Andric for (;I != MBB->begin(); --I) {
5080b57cec5SDimitry Andric MachineInstr &MI = *std::prev(I);
5090b57cec5SDimitry Andric if (isSchedBoundary(&MI, &*MBB, MF, TII))
5100b57cec5SDimitry Andric break;
511*5f7ddb14SDimitry Andric if (!MI.isDebugOrPseudoInstr()) {
5120b57cec5SDimitry Andric // MBB::size() uses instr_iterator to count. Here we need a bundle to
5130b57cec5SDimitry Andric // count as a single instruction.
5140b57cec5SDimitry Andric ++NumRegionInstrs;
5150b57cec5SDimitry Andric }
5160b57cec5SDimitry Andric }
5170b57cec5SDimitry Andric
5180b57cec5SDimitry Andric // It's possible we found a scheduling region that only has debug
5190b57cec5SDimitry Andric // instructions. Don't bother scheduling these.
5200b57cec5SDimitry Andric if (NumRegionInstrs != 0)
5210b57cec5SDimitry Andric Regions.push_back(SchedRegion(I, RegionEnd, NumRegionInstrs));
5220b57cec5SDimitry Andric }
5230b57cec5SDimitry Andric
5240b57cec5SDimitry Andric if (RegionsTopDown)
5250b57cec5SDimitry Andric std::reverse(Regions.begin(), Regions.end());
5260b57cec5SDimitry Andric }
5270b57cec5SDimitry Andric
5280b57cec5SDimitry Andric /// Main driver for both MachineScheduler and PostMachineScheduler.
scheduleRegions(ScheduleDAGInstrs & Scheduler,bool FixKillFlags)5290b57cec5SDimitry Andric void MachineSchedulerBase::scheduleRegions(ScheduleDAGInstrs &Scheduler,
5300b57cec5SDimitry Andric bool FixKillFlags) {
5310b57cec5SDimitry Andric // Visit all machine basic blocks.
5320b57cec5SDimitry Andric //
5330b57cec5SDimitry Andric // TODO: Visit blocks in global postorder or postorder within the bottom-up
5340b57cec5SDimitry Andric // loop tree. Then we can optionally compute global RegPressure.
5350b57cec5SDimitry Andric for (MachineFunction::iterator MBB = MF->begin(), MBBEnd = MF->end();
5360b57cec5SDimitry Andric MBB != MBBEnd; ++MBB) {
5370b57cec5SDimitry Andric
5380b57cec5SDimitry Andric Scheduler.startBlock(&*MBB);
5390b57cec5SDimitry Andric
5400b57cec5SDimitry Andric #ifndef NDEBUG
5410b57cec5SDimitry Andric if (SchedOnlyFunc.getNumOccurrences() && SchedOnlyFunc != MF->getName())
5420b57cec5SDimitry Andric continue;
5430b57cec5SDimitry Andric if (SchedOnlyBlock.getNumOccurrences()
5440b57cec5SDimitry Andric && (int)SchedOnlyBlock != MBB->getNumber())
5450b57cec5SDimitry Andric continue;
5460b57cec5SDimitry Andric #endif
5470b57cec5SDimitry Andric
5480b57cec5SDimitry Andric // Break the block into scheduling regions [I, RegionEnd). RegionEnd
5490b57cec5SDimitry Andric // points to the scheduling boundary at the bottom of the region. The DAG
5500b57cec5SDimitry Andric // does not include RegionEnd, but the region does (i.e. the next
5510b57cec5SDimitry Andric // RegionEnd is above the previous RegionBegin). If the current block has
5520b57cec5SDimitry Andric // no terminator then RegionEnd == MBB->end() for the bottom region.
5530b57cec5SDimitry Andric //
5540b57cec5SDimitry Andric // All the regions of MBB are first found and stored in MBBRegions, which
5550b57cec5SDimitry Andric // will be processed (MBB) top-down if initialized with true.
5560b57cec5SDimitry Andric //
5570b57cec5SDimitry Andric // The Scheduler may insert instructions during either schedule() or
5580b57cec5SDimitry Andric // exitRegion(), even for empty regions. So the local iterators 'I' and
5590b57cec5SDimitry Andric // 'RegionEnd' are invalid across these calls. Instructions must not be
5600b57cec5SDimitry Andric // added to other regions than the current one without updating MBBRegions.
5610b57cec5SDimitry Andric
5620b57cec5SDimitry Andric MBBRegionsVector MBBRegions;
5630b57cec5SDimitry Andric getSchedRegions(&*MBB, MBBRegions, Scheduler.doMBBSchedRegionsTopDown());
5640b57cec5SDimitry Andric for (MBBRegionsVector::iterator R = MBBRegions.begin();
5650b57cec5SDimitry Andric R != MBBRegions.end(); ++R) {
5660b57cec5SDimitry Andric MachineBasicBlock::iterator I = R->RegionBegin;
5670b57cec5SDimitry Andric MachineBasicBlock::iterator RegionEnd = R->RegionEnd;
5680b57cec5SDimitry Andric unsigned NumRegionInstrs = R->NumRegionInstrs;
5690b57cec5SDimitry Andric
5700b57cec5SDimitry Andric // Notify the scheduler of the region, even if we may skip scheduling
5710b57cec5SDimitry Andric // it. Perhaps it still needs to be bundled.
5720b57cec5SDimitry Andric Scheduler.enterRegion(&*MBB, I, RegionEnd, NumRegionInstrs);
5730b57cec5SDimitry Andric
5740b57cec5SDimitry Andric // Skip empty scheduling regions (0 or 1 schedulable instructions).
5750b57cec5SDimitry Andric if (I == RegionEnd || I == std::prev(RegionEnd)) {
5760b57cec5SDimitry Andric // Close the current region. Bundle the terminator if needed.
5770b57cec5SDimitry Andric // This invalidates 'RegionEnd' and 'I'.
5780b57cec5SDimitry Andric Scheduler.exitRegion();
5790b57cec5SDimitry Andric continue;
5800b57cec5SDimitry Andric }
5810b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "********** MI Scheduling **********\n");
5820b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << MF->getName() << ":" << printMBBReference(*MBB)
5830b57cec5SDimitry Andric << " " << MBB->getName() << "\n From: " << *I
5840b57cec5SDimitry Andric << " To: ";
5850b57cec5SDimitry Andric if (RegionEnd != MBB->end()) dbgs() << *RegionEnd;
5860b57cec5SDimitry Andric else dbgs() << "End";
5870b57cec5SDimitry Andric dbgs() << " RegionInstrs: " << NumRegionInstrs << '\n');
5880b57cec5SDimitry Andric if (DumpCriticalPathLength) {
5890b57cec5SDimitry Andric errs() << MF->getName();
5900b57cec5SDimitry Andric errs() << ":%bb. " << MBB->getNumber();
5910b57cec5SDimitry Andric errs() << " " << MBB->getName() << " \n";
5920b57cec5SDimitry Andric }
5930b57cec5SDimitry Andric
5940b57cec5SDimitry Andric // Schedule a region: possibly reorder instructions.
5950b57cec5SDimitry Andric // This invalidates the original region iterators.
5960b57cec5SDimitry Andric Scheduler.schedule();
5970b57cec5SDimitry Andric
5980b57cec5SDimitry Andric // Close the current region.
5990b57cec5SDimitry Andric Scheduler.exitRegion();
6000b57cec5SDimitry Andric }
6010b57cec5SDimitry Andric Scheduler.finishBlock();
6020b57cec5SDimitry Andric // FIXME: Ideally, no further passes should rely on kill flags. However,
6030b57cec5SDimitry Andric // thumb2 size reduction is currently an exception, so the PostMIScheduler
6040b57cec5SDimitry Andric // needs to do this.
6050b57cec5SDimitry Andric if (FixKillFlags)
6060b57cec5SDimitry Andric Scheduler.fixupKills(*MBB);
6070b57cec5SDimitry Andric }
6080b57cec5SDimitry Andric Scheduler.finalizeSchedule();
6090b57cec5SDimitry Andric }
6100b57cec5SDimitry Andric
print(raw_ostream & O,const Module * m) const6110b57cec5SDimitry Andric void MachineSchedulerBase::print(raw_ostream &O, const Module* m) const {
6120b57cec5SDimitry Andric // unimplemented
6130b57cec5SDimitry Andric }
6140b57cec5SDimitry Andric
6150b57cec5SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
dump() const6160b57cec5SDimitry Andric LLVM_DUMP_METHOD void ReadyQueue::dump() const {
6170b57cec5SDimitry Andric dbgs() << "Queue " << Name << ": ";
6180b57cec5SDimitry Andric for (const SUnit *SU : Queue)
6190b57cec5SDimitry Andric dbgs() << SU->NodeNum << " ";
6200b57cec5SDimitry Andric dbgs() << "\n";
6210b57cec5SDimitry Andric }
6220b57cec5SDimitry Andric #endif
6230b57cec5SDimitry Andric
6240b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
6250b57cec5SDimitry Andric // ScheduleDAGMI - Basic machine instruction scheduling. This is
6260b57cec5SDimitry Andric // independent of PreRA/PostRA scheduling and involves no extra book-keeping for
6270b57cec5SDimitry Andric // virtual registers.
6280b57cec5SDimitry Andric // ===----------------------------------------------------------------------===/
6290b57cec5SDimitry Andric
6300b57cec5SDimitry Andric // Provide a vtable anchor.
6310b57cec5SDimitry Andric ScheduleDAGMI::~ScheduleDAGMI() = default;
6320b57cec5SDimitry Andric
6330b57cec5SDimitry Andric /// ReleaseSucc - Decrement the NumPredsLeft count of a successor. When
6340b57cec5SDimitry Andric /// NumPredsLeft reaches zero, release the successor node.
6350b57cec5SDimitry Andric ///
6360b57cec5SDimitry Andric /// FIXME: Adjust SuccSU height based on MinLatency.
releaseSucc(SUnit * SU,SDep * SuccEdge)6370b57cec5SDimitry Andric void ScheduleDAGMI::releaseSucc(SUnit *SU, SDep *SuccEdge) {
6380b57cec5SDimitry Andric SUnit *SuccSU = SuccEdge->getSUnit();
6390b57cec5SDimitry Andric
6400b57cec5SDimitry Andric if (SuccEdge->isWeak()) {
6410b57cec5SDimitry Andric --SuccSU->WeakPredsLeft;
6420b57cec5SDimitry Andric if (SuccEdge->isCluster())
6430b57cec5SDimitry Andric NextClusterSucc = SuccSU;
6440b57cec5SDimitry Andric return;
6450b57cec5SDimitry Andric }
6460b57cec5SDimitry Andric #ifndef NDEBUG
6470b57cec5SDimitry Andric if (SuccSU->NumPredsLeft == 0) {
6480b57cec5SDimitry Andric dbgs() << "*** Scheduling failed! ***\n";
6490b57cec5SDimitry Andric dumpNode(*SuccSU);
6500b57cec5SDimitry Andric dbgs() << " has been released too many times!\n";
6510b57cec5SDimitry Andric llvm_unreachable(nullptr);
6520b57cec5SDimitry Andric }
6530b57cec5SDimitry Andric #endif
6540b57cec5SDimitry Andric // SU->TopReadyCycle was set to CurrCycle when it was scheduled. However,
6550b57cec5SDimitry Andric // CurrCycle may have advanced since then.
6560b57cec5SDimitry Andric if (SuccSU->TopReadyCycle < SU->TopReadyCycle + SuccEdge->getLatency())
6570b57cec5SDimitry Andric SuccSU->TopReadyCycle = SU->TopReadyCycle + SuccEdge->getLatency();
6580b57cec5SDimitry Andric
6590b57cec5SDimitry Andric --SuccSU->NumPredsLeft;
6600b57cec5SDimitry Andric if (SuccSU->NumPredsLeft == 0 && SuccSU != &ExitSU)
6610b57cec5SDimitry Andric SchedImpl->releaseTopNode(SuccSU);
6620b57cec5SDimitry Andric }
6630b57cec5SDimitry Andric
6640b57cec5SDimitry Andric /// releaseSuccessors - Call releaseSucc on each of SU's successors.
releaseSuccessors(SUnit * SU)6650b57cec5SDimitry Andric void ScheduleDAGMI::releaseSuccessors(SUnit *SU) {
6660b57cec5SDimitry Andric for (SDep &Succ : SU->Succs)
6670b57cec5SDimitry Andric releaseSucc(SU, &Succ);
6680b57cec5SDimitry Andric }
6690b57cec5SDimitry Andric
6700b57cec5SDimitry Andric /// ReleasePred - Decrement the NumSuccsLeft count of a predecessor. When
6710b57cec5SDimitry Andric /// NumSuccsLeft reaches zero, release the predecessor node.
6720b57cec5SDimitry Andric ///
6730b57cec5SDimitry Andric /// FIXME: Adjust PredSU height based on MinLatency.
releasePred(SUnit * SU,SDep * PredEdge)6740b57cec5SDimitry Andric void ScheduleDAGMI::releasePred(SUnit *SU, SDep *PredEdge) {
6750b57cec5SDimitry Andric SUnit *PredSU = PredEdge->getSUnit();
6760b57cec5SDimitry Andric
6770b57cec5SDimitry Andric if (PredEdge->isWeak()) {
6780b57cec5SDimitry Andric --PredSU->WeakSuccsLeft;
6790b57cec5SDimitry Andric if (PredEdge->isCluster())
6800b57cec5SDimitry Andric NextClusterPred = PredSU;
6810b57cec5SDimitry Andric return;
6820b57cec5SDimitry Andric }
6830b57cec5SDimitry Andric #ifndef NDEBUG
6840b57cec5SDimitry Andric if (PredSU->NumSuccsLeft == 0) {
6850b57cec5SDimitry Andric dbgs() << "*** Scheduling failed! ***\n";
6860b57cec5SDimitry Andric dumpNode(*PredSU);
6870b57cec5SDimitry Andric dbgs() << " has been released too many times!\n";
6880b57cec5SDimitry Andric llvm_unreachable(nullptr);
6890b57cec5SDimitry Andric }
6900b57cec5SDimitry Andric #endif
6910b57cec5SDimitry Andric // SU->BotReadyCycle was set to CurrCycle when it was scheduled. However,
6920b57cec5SDimitry Andric // CurrCycle may have advanced since then.
6930b57cec5SDimitry Andric if (PredSU->BotReadyCycle < SU->BotReadyCycle + PredEdge->getLatency())
6940b57cec5SDimitry Andric PredSU->BotReadyCycle = SU->BotReadyCycle + PredEdge->getLatency();
6950b57cec5SDimitry Andric
6960b57cec5SDimitry Andric --PredSU->NumSuccsLeft;
6970b57cec5SDimitry Andric if (PredSU->NumSuccsLeft == 0 && PredSU != &EntrySU)
6980b57cec5SDimitry Andric SchedImpl->releaseBottomNode(PredSU);
6990b57cec5SDimitry Andric }
7000b57cec5SDimitry Andric
7010b57cec5SDimitry Andric /// releasePredecessors - Call releasePred on each of SU's predecessors.
releasePredecessors(SUnit * SU)7020b57cec5SDimitry Andric void ScheduleDAGMI::releasePredecessors(SUnit *SU) {
7030b57cec5SDimitry Andric for (SDep &Pred : SU->Preds)
7040b57cec5SDimitry Andric releasePred(SU, &Pred);
7050b57cec5SDimitry Andric }
7060b57cec5SDimitry Andric
startBlock(MachineBasicBlock * bb)7070b57cec5SDimitry Andric void ScheduleDAGMI::startBlock(MachineBasicBlock *bb) {
7080b57cec5SDimitry Andric ScheduleDAGInstrs::startBlock(bb);
7090b57cec5SDimitry Andric SchedImpl->enterMBB(bb);
7100b57cec5SDimitry Andric }
7110b57cec5SDimitry Andric
finishBlock()7120b57cec5SDimitry Andric void ScheduleDAGMI::finishBlock() {
7130b57cec5SDimitry Andric SchedImpl->leaveMBB();
7140b57cec5SDimitry Andric ScheduleDAGInstrs::finishBlock();
7150b57cec5SDimitry Andric }
7160b57cec5SDimitry Andric
7170b57cec5SDimitry Andric /// enterRegion - Called back from MachineScheduler::runOnMachineFunction after
7180b57cec5SDimitry Andric /// crossing a scheduling boundary. [begin, end) includes all instructions in
7190b57cec5SDimitry Andric /// the region, including the boundary itself and single-instruction regions
7200b57cec5SDimitry Andric /// that don't get scheduled.
enterRegion(MachineBasicBlock * bb,MachineBasicBlock::iterator begin,MachineBasicBlock::iterator end,unsigned regioninstrs)7210b57cec5SDimitry Andric void ScheduleDAGMI::enterRegion(MachineBasicBlock *bb,
7220b57cec5SDimitry Andric MachineBasicBlock::iterator begin,
7230b57cec5SDimitry Andric MachineBasicBlock::iterator end,
7240b57cec5SDimitry Andric unsigned regioninstrs)
7250b57cec5SDimitry Andric {
7260b57cec5SDimitry Andric ScheduleDAGInstrs::enterRegion(bb, begin, end, regioninstrs);
7270b57cec5SDimitry Andric
7280b57cec5SDimitry Andric SchedImpl->initPolicy(begin, end, regioninstrs);
7290b57cec5SDimitry Andric }
7300b57cec5SDimitry Andric
7310b57cec5SDimitry Andric /// This is normally called from the main scheduler loop but may also be invoked
7320b57cec5SDimitry Andric /// by the scheduling strategy to perform additional code motion.
moveInstruction(MachineInstr * MI,MachineBasicBlock::iterator InsertPos)7330b57cec5SDimitry Andric void ScheduleDAGMI::moveInstruction(
7340b57cec5SDimitry Andric MachineInstr *MI, MachineBasicBlock::iterator InsertPos) {
7350b57cec5SDimitry Andric // Advance RegionBegin if the first instruction moves down.
7360b57cec5SDimitry Andric if (&*RegionBegin == MI)
7370b57cec5SDimitry Andric ++RegionBegin;
7380b57cec5SDimitry Andric
7390b57cec5SDimitry Andric // Update the instruction stream.
7400b57cec5SDimitry Andric BB->splice(InsertPos, BB, MI);
7410b57cec5SDimitry Andric
7420b57cec5SDimitry Andric // Update LiveIntervals
7430b57cec5SDimitry Andric if (LIS)
7440b57cec5SDimitry Andric LIS->handleMove(*MI, /*UpdateFlags=*/true);
7450b57cec5SDimitry Andric
7460b57cec5SDimitry Andric // Recede RegionBegin if an instruction moves above the first.
7470b57cec5SDimitry Andric if (RegionBegin == InsertPos)
7480b57cec5SDimitry Andric RegionBegin = MI;
7490b57cec5SDimitry Andric }
7500b57cec5SDimitry Andric
checkSchedLimit()7510b57cec5SDimitry Andric bool ScheduleDAGMI::checkSchedLimit() {
7520b57cec5SDimitry Andric #ifndef NDEBUG
7530b57cec5SDimitry Andric if (NumInstrsScheduled == MISchedCutoff && MISchedCutoff != ~0U) {
7540b57cec5SDimitry Andric CurrentTop = CurrentBottom;
7550b57cec5SDimitry Andric return false;
7560b57cec5SDimitry Andric }
7570b57cec5SDimitry Andric ++NumInstrsScheduled;
7580b57cec5SDimitry Andric #endif
7590b57cec5SDimitry Andric return true;
7600b57cec5SDimitry Andric }
7610b57cec5SDimitry Andric
7620b57cec5SDimitry Andric /// Per-region scheduling driver, called back from
7630b57cec5SDimitry Andric /// MachineScheduler::runOnMachineFunction. This is a simplified driver that
7640b57cec5SDimitry Andric /// does not consider liveness or register pressure. It is useful for PostRA
7650b57cec5SDimitry Andric /// scheduling and potentially other custom schedulers.
schedule()7660b57cec5SDimitry Andric void ScheduleDAGMI::schedule() {
7670b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "ScheduleDAGMI::schedule starting\n");
7680b57cec5SDimitry Andric LLVM_DEBUG(SchedImpl->dumpPolicy());
7690b57cec5SDimitry Andric
7700b57cec5SDimitry Andric // Build the DAG.
7710b57cec5SDimitry Andric buildSchedGraph(AA);
7720b57cec5SDimitry Andric
7730b57cec5SDimitry Andric postprocessDAG();
7740b57cec5SDimitry Andric
7750b57cec5SDimitry Andric SmallVector<SUnit*, 8> TopRoots, BotRoots;
7760b57cec5SDimitry Andric findRootsAndBiasEdges(TopRoots, BotRoots);
7770b57cec5SDimitry Andric
7780b57cec5SDimitry Andric LLVM_DEBUG(dump());
7790b57cec5SDimitry Andric if (PrintDAGs) dump();
7800b57cec5SDimitry Andric if (ViewMISchedDAGs) viewGraph();
7810b57cec5SDimitry Andric
7820b57cec5SDimitry Andric // Initialize the strategy before modifying the DAG.
7830b57cec5SDimitry Andric // This may initialize a DFSResult to be used for queue priority.
7840b57cec5SDimitry Andric SchedImpl->initialize(this);
7850b57cec5SDimitry Andric
7860b57cec5SDimitry Andric // Initialize ready queues now that the DAG and priority data are finalized.
7870b57cec5SDimitry Andric initQueues(TopRoots, BotRoots);
7880b57cec5SDimitry Andric
7890b57cec5SDimitry Andric bool IsTopNode = false;
7900b57cec5SDimitry Andric while (true) {
7910b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "** ScheduleDAGMI::schedule picking next node\n");
7920b57cec5SDimitry Andric SUnit *SU = SchedImpl->pickNode(IsTopNode);
7930b57cec5SDimitry Andric if (!SU) break;
7940b57cec5SDimitry Andric
7950b57cec5SDimitry Andric assert(!SU->isScheduled && "Node already scheduled");
7960b57cec5SDimitry Andric if (!checkSchedLimit())
7970b57cec5SDimitry Andric break;
7980b57cec5SDimitry Andric
7990b57cec5SDimitry Andric MachineInstr *MI = SU->getInstr();
8000b57cec5SDimitry Andric if (IsTopNode) {
8010b57cec5SDimitry Andric assert(SU->isTopReady() && "node still has unscheduled dependencies");
8020b57cec5SDimitry Andric if (&*CurrentTop == MI)
8030b57cec5SDimitry Andric CurrentTop = nextIfDebug(++CurrentTop, CurrentBottom);
8040b57cec5SDimitry Andric else
8050b57cec5SDimitry Andric moveInstruction(MI, CurrentTop);
8060b57cec5SDimitry Andric } else {
8070b57cec5SDimitry Andric assert(SU->isBottomReady() && "node still has unscheduled dependencies");
8080b57cec5SDimitry Andric MachineBasicBlock::iterator priorII =
8090b57cec5SDimitry Andric priorNonDebug(CurrentBottom, CurrentTop);
8100b57cec5SDimitry Andric if (&*priorII == MI)
8110b57cec5SDimitry Andric CurrentBottom = priorII;
8120b57cec5SDimitry Andric else {
8130b57cec5SDimitry Andric if (&*CurrentTop == MI)
8140b57cec5SDimitry Andric CurrentTop = nextIfDebug(++CurrentTop, priorII);
8150b57cec5SDimitry Andric moveInstruction(MI, CurrentBottom);
8160b57cec5SDimitry Andric CurrentBottom = MI;
8170b57cec5SDimitry Andric }
8180b57cec5SDimitry Andric }
8190b57cec5SDimitry Andric // Notify the scheduling strategy before updating the DAG.
8200b57cec5SDimitry Andric // This sets the scheduled node's ReadyCycle to CurrCycle. When updateQueues
8210b57cec5SDimitry Andric // runs, it can then use the accurate ReadyCycle time to determine whether
8220b57cec5SDimitry Andric // newly released nodes can move to the readyQ.
8230b57cec5SDimitry Andric SchedImpl->schedNode(SU, IsTopNode);
8240b57cec5SDimitry Andric
8250b57cec5SDimitry Andric updateQueues(SU, IsTopNode);
8260b57cec5SDimitry Andric }
8270b57cec5SDimitry Andric assert(CurrentTop == CurrentBottom && "Nonempty unscheduled zone.");
8280b57cec5SDimitry Andric
8290b57cec5SDimitry Andric placeDebugValues();
8300b57cec5SDimitry Andric
8310b57cec5SDimitry Andric LLVM_DEBUG({
8320b57cec5SDimitry Andric dbgs() << "*** Final schedule for "
8330b57cec5SDimitry Andric << printMBBReference(*begin()->getParent()) << " ***\n";
8340b57cec5SDimitry Andric dumpSchedule();
8350b57cec5SDimitry Andric dbgs() << '\n';
8360b57cec5SDimitry Andric });
8370b57cec5SDimitry Andric }
8380b57cec5SDimitry Andric
8390b57cec5SDimitry Andric /// Apply each ScheduleDAGMutation step in order.
postprocessDAG()8400b57cec5SDimitry Andric void ScheduleDAGMI::postprocessDAG() {
8410b57cec5SDimitry Andric for (auto &m : Mutations)
8420b57cec5SDimitry Andric m->apply(this);
8430b57cec5SDimitry Andric }
8440b57cec5SDimitry Andric
8450b57cec5SDimitry Andric void ScheduleDAGMI::
findRootsAndBiasEdges(SmallVectorImpl<SUnit * > & TopRoots,SmallVectorImpl<SUnit * > & BotRoots)8460b57cec5SDimitry Andric findRootsAndBiasEdges(SmallVectorImpl<SUnit*> &TopRoots,
8470b57cec5SDimitry Andric SmallVectorImpl<SUnit*> &BotRoots) {
8480b57cec5SDimitry Andric for (SUnit &SU : SUnits) {
8490b57cec5SDimitry Andric assert(!SU.isBoundaryNode() && "Boundary node should not be in SUnits");
8500b57cec5SDimitry Andric
8510b57cec5SDimitry Andric // Order predecessors so DFSResult follows the critical path.
8520b57cec5SDimitry Andric SU.biasCriticalPath();
8530b57cec5SDimitry Andric
8540b57cec5SDimitry Andric // A SUnit is ready to top schedule if it has no predecessors.
8550b57cec5SDimitry Andric if (!SU.NumPredsLeft)
8560b57cec5SDimitry Andric TopRoots.push_back(&SU);
8570b57cec5SDimitry Andric // A SUnit is ready to bottom schedule if it has no successors.
8580b57cec5SDimitry Andric if (!SU.NumSuccsLeft)
8590b57cec5SDimitry Andric BotRoots.push_back(&SU);
8600b57cec5SDimitry Andric }
8610b57cec5SDimitry Andric ExitSU.biasCriticalPath();
8620b57cec5SDimitry Andric }
8630b57cec5SDimitry Andric
8640b57cec5SDimitry Andric /// Identify DAG roots and setup scheduler queues.
initQueues(ArrayRef<SUnit * > TopRoots,ArrayRef<SUnit * > BotRoots)8650b57cec5SDimitry Andric void ScheduleDAGMI::initQueues(ArrayRef<SUnit*> TopRoots,
8660b57cec5SDimitry Andric ArrayRef<SUnit*> BotRoots) {
8670b57cec5SDimitry Andric NextClusterSucc = nullptr;
8680b57cec5SDimitry Andric NextClusterPred = nullptr;
8690b57cec5SDimitry Andric
8700b57cec5SDimitry Andric // Release all DAG roots for scheduling, not including EntrySU/ExitSU.
8710b57cec5SDimitry Andric //
8720b57cec5SDimitry Andric // Nodes with unreleased weak edges can still be roots.
8730b57cec5SDimitry Andric // Release top roots in forward order.
8740b57cec5SDimitry Andric for (SUnit *SU : TopRoots)
8750b57cec5SDimitry Andric SchedImpl->releaseTopNode(SU);
8760b57cec5SDimitry Andric
8770b57cec5SDimitry Andric // Release bottom roots in reverse order so the higher priority nodes appear
8780b57cec5SDimitry Andric // first. This is more natural and slightly more efficient.
8790b57cec5SDimitry Andric for (SmallVectorImpl<SUnit*>::const_reverse_iterator
8800b57cec5SDimitry Andric I = BotRoots.rbegin(), E = BotRoots.rend(); I != E; ++I) {
8810b57cec5SDimitry Andric SchedImpl->releaseBottomNode(*I);
8820b57cec5SDimitry Andric }
8830b57cec5SDimitry Andric
8840b57cec5SDimitry Andric releaseSuccessors(&EntrySU);
8850b57cec5SDimitry Andric releasePredecessors(&ExitSU);
8860b57cec5SDimitry Andric
8870b57cec5SDimitry Andric SchedImpl->registerRoots();
8880b57cec5SDimitry Andric
8890b57cec5SDimitry Andric // Advance past initial DebugValues.
8900b57cec5SDimitry Andric CurrentTop = nextIfDebug(RegionBegin, RegionEnd);
8910b57cec5SDimitry Andric CurrentBottom = RegionEnd;
8920b57cec5SDimitry Andric }
8930b57cec5SDimitry Andric
8940b57cec5SDimitry Andric /// Update scheduler queues after scheduling an instruction.
updateQueues(SUnit * SU,bool IsTopNode)8950b57cec5SDimitry Andric void ScheduleDAGMI::updateQueues(SUnit *SU, bool IsTopNode) {
8960b57cec5SDimitry Andric // Release dependent instructions for scheduling.
8970b57cec5SDimitry Andric if (IsTopNode)
8980b57cec5SDimitry Andric releaseSuccessors(SU);
8990b57cec5SDimitry Andric else
9000b57cec5SDimitry Andric releasePredecessors(SU);
9010b57cec5SDimitry Andric
9020b57cec5SDimitry Andric SU->isScheduled = true;
9030b57cec5SDimitry Andric }
9040b57cec5SDimitry Andric
9050b57cec5SDimitry Andric /// Reinsert any remaining debug_values, just like the PostRA scheduler.
placeDebugValues()9060b57cec5SDimitry Andric void ScheduleDAGMI::placeDebugValues() {
9070b57cec5SDimitry Andric // If first instruction was a DBG_VALUE then put it back.
9080b57cec5SDimitry Andric if (FirstDbgValue) {
9090b57cec5SDimitry Andric BB->splice(RegionBegin, BB, FirstDbgValue);
9100b57cec5SDimitry Andric RegionBegin = FirstDbgValue;
9110b57cec5SDimitry Andric }
9120b57cec5SDimitry Andric
9130b57cec5SDimitry Andric for (std::vector<std::pair<MachineInstr *, MachineInstr *>>::iterator
9140b57cec5SDimitry Andric DI = DbgValues.end(), DE = DbgValues.begin(); DI != DE; --DI) {
9150b57cec5SDimitry Andric std::pair<MachineInstr *, MachineInstr *> P = *std::prev(DI);
9160b57cec5SDimitry Andric MachineInstr *DbgValue = P.first;
9170b57cec5SDimitry Andric MachineBasicBlock::iterator OrigPrevMI = P.second;
9180b57cec5SDimitry Andric if (&*RegionBegin == DbgValue)
9190b57cec5SDimitry Andric ++RegionBegin;
9200b57cec5SDimitry Andric BB->splice(++OrigPrevMI, BB, DbgValue);
9210b57cec5SDimitry Andric if (OrigPrevMI == std::prev(RegionEnd))
9220b57cec5SDimitry Andric RegionEnd = DbgValue;
9230b57cec5SDimitry Andric }
9240b57cec5SDimitry Andric DbgValues.clear();
9250b57cec5SDimitry Andric FirstDbgValue = nullptr;
9260b57cec5SDimitry Andric }
9270b57cec5SDimitry Andric
9280b57cec5SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
dumpSchedule() const9290b57cec5SDimitry Andric LLVM_DUMP_METHOD void ScheduleDAGMI::dumpSchedule() const {
930*5f7ddb14SDimitry Andric for (MachineInstr &MI : *this) {
931*5f7ddb14SDimitry Andric if (SUnit *SU = getSUnit(&MI))
9320b57cec5SDimitry Andric dumpNode(*SU);
9330b57cec5SDimitry Andric else
9340b57cec5SDimitry Andric dbgs() << "Missing SUnit\n";
9350b57cec5SDimitry Andric }
9360b57cec5SDimitry Andric }
9370b57cec5SDimitry Andric #endif
9380b57cec5SDimitry Andric
9390b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
9400b57cec5SDimitry Andric // ScheduleDAGMILive - Base class for MachineInstr scheduling with LiveIntervals
9410b57cec5SDimitry Andric // preservation.
9420b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
9430b57cec5SDimitry Andric
~ScheduleDAGMILive()9440b57cec5SDimitry Andric ScheduleDAGMILive::~ScheduleDAGMILive() {
9450b57cec5SDimitry Andric delete DFSResult;
9460b57cec5SDimitry Andric }
9470b57cec5SDimitry Andric
collectVRegUses(SUnit & SU)9480b57cec5SDimitry Andric void ScheduleDAGMILive::collectVRegUses(SUnit &SU) {
9490b57cec5SDimitry Andric const MachineInstr &MI = *SU.getInstr();
9500b57cec5SDimitry Andric for (const MachineOperand &MO : MI.operands()) {
9510b57cec5SDimitry Andric if (!MO.isReg())
9520b57cec5SDimitry Andric continue;
9530b57cec5SDimitry Andric if (!MO.readsReg())
9540b57cec5SDimitry Andric continue;
9550b57cec5SDimitry Andric if (TrackLaneMasks && !MO.isUse())
9560b57cec5SDimitry Andric continue;
9570b57cec5SDimitry Andric
9588bcb0991SDimitry Andric Register Reg = MO.getReg();
9598bcb0991SDimitry Andric if (!Register::isVirtualRegister(Reg))
9600b57cec5SDimitry Andric continue;
9610b57cec5SDimitry Andric
9620b57cec5SDimitry Andric // Ignore re-defs.
9630b57cec5SDimitry Andric if (TrackLaneMasks) {
9640b57cec5SDimitry Andric bool FoundDef = false;
9650b57cec5SDimitry Andric for (const MachineOperand &MO2 : MI.operands()) {
9660b57cec5SDimitry Andric if (MO2.isReg() && MO2.isDef() && MO2.getReg() == Reg && !MO2.isDead()) {
9670b57cec5SDimitry Andric FoundDef = true;
9680b57cec5SDimitry Andric break;
9690b57cec5SDimitry Andric }
9700b57cec5SDimitry Andric }
9710b57cec5SDimitry Andric if (FoundDef)
9720b57cec5SDimitry Andric continue;
9730b57cec5SDimitry Andric }
9740b57cec5SDimitry Andric
9750b57cec5SDimitry Andric // Record this local VReg use.
9760b57cec5SDimitry Andric VReg2SUnitMultiMap::iterator UI = VRegUses.find(Reg);
9770b57cec5SDimitry Andric for (; UI != VRegUses.end(); ++UI) {
9780b57cec5SDimitry Andric if (UI->SU == &SU)
9790b57cec5SDimitry Andric break;
9800b57cec5SDimitry Andric }
9810b57cec5SDimitry Andric if (UI == VRegUses.end())
9820b57cec5SDimitry Andric VRegUses.insert(VReg2SUnit(Reg, LaneBitmask::getNone(), &SU));
9830b57cec5SDimitry Andric }
9840b57cec5SDimitry Andric }
9850b57cec5SDimitry Andric
9860b57cec5SDimitry Andric /// enterRegion - Called back from MachineScheduler::runOnMachineFunction after
9870b57cec5SDimitry Andric /// crossing a scheduling boundary. [begin, end) includes all instructions in
9880b57cec5SDimitry Andric /// the region, including the boundary itself and single-instruction regions
9890b57cec5SDimitry Andric /// that don't get scheduled.
enterRegion(MachineBasicBlock * bb,MachineBasicBlock::iterator begin,MachineBasicBlock::iterator end,unsigned regioninstrs)9900b57cec5SDimitry Andric void ScheduleDAGMILive::enterRegion(MachineBasicBlock *bb,
9910b57cec5SDimitry Andric MachineBasicBlock::iterator begin,
9920b57cec5SDimitry Andric MachineBasicBlock::iterator end,
9930b57cec5SDimitry Andric unsigned regioninstrs)
9940b57cec5SDimitry Andric {
9950b57cec5SDimitry Andric // ScheduleDAGMI initializes SchedImpl's per-region policy.
9960b57cec5SDimitry Andric ScheduleDAGMI::enterRegion(bb, begin, end, regioninstrs);
9970b57cec5SDimitry Andric
9980b57cec5SDimitry Andric // For convenience remember the end of the liveness region.
9990b57cec5SDimitry Andric LiveRegionEnd = (RegionEnd == bb->end()) ? RegionEnd : std::next(RegionEnd);
10000b57cec5SDimitry Andric
10010b57cec5SDimitry Andric SUPressureDiffs.clear();
10020b57cec5SDimitry Andric
10030b57cec5SDimitry Andric ShouldTrackPressure = SchedImpl->shouldTrackPressure();
10040b57cec5SDimitry Andric ShouldTrackLaneMasks = SchedImpl->shouldTrackLaneMasks();
10050b57cec5SDimitry Andric
10060b57cec5SDimitry Andric assert((!ShouldTrackLaneMasks || ShouldTrackPressure) &&
10070b57cec5SDimitry Andric "ShouldTrackLaneMasks requires ShouldTrackPressure");
10080b57cec5SDimitry Andric }
10090b57cec5SDimitry Andric
10108bcb0991SDimitry Andric // Setup the register pressure trackers for the top scheduled and bottom
10110b57cec5SDimitry Andric // scheduled regions.
initRegPressure()10120b57cec5SDimitry Andric void ScheduleDAGMILive::initRegPressure() {
10130b57cec5SDimitry Andric VRegUses.clear();
10140b57cec5SDimitry Andric VRegUses.setUniverse(MRI.getNumVirtRegs());
10150b57cec5SDimitry Andric for (SUnit &SU : SUnits)
10160b57cec5SDimitry Andric collectVRegUses(SU);
10170b57cec5SDimitry Andric
10180b57cec5SDimitry Andric TopRPTracker.init(&MF, RegClassInfo, LIS, BB, RegionBegin,
10190b57cec5SDimitry Andric ShouldTrackLaneMasks, false);
10200b57cec5SDimitry Andric BotRPTracker.init(&MF, RegClassInfo, LIS, BB, LiveRegionEnd,
10210b57cec5SDimitry Andric ShouldTrackLaneMasks, false);
10220b57cec5SDimitry Andric
10230b57cec5SDimitry Andric // Close the RPTracker to finalize live ins.
10240b57cec5SDimitry Andric RPTracker.closeRegion();
10250b57cec5SDimitry Andric
10260b57cec5SDimitry Andric LLVM_DEBUG(RPTracker.dump());
10270b57cec5SDimitry Andric
10280b57cec5SDimitry Andric // Initialize the live ins and live outs.
10290b57cec5SDimitry Andric TopRPTracker.addLiveRegs(RPTracker.getPressure().LiveInRegs);
10300b57cec5SDimitry Andric BotRPTracker.addLiveRegs(RPTracker.getPressure().LiveOutRegs);
10310b57cec5SDimitry Andric
10320b57cec5SDimitry Andric // Close one end of the tracker so we can call
10330b57cec5SDimitry Andric // getMaxUpward/DownwardPressureDelta before advancing across any
10340b57cec5SDimitry Andric // instructions. This converts currently live regs into live ins/outs.
10350b57cec5SDimitry Andric TopRPTracker.closeTop();
10360b57cec5SDimitry Andric BotRPTracker.closeBottom();
10370b57cec5SDimitry Andric
10380b57cec5SDimitry Andric BotRPTracker.initLiveThru(RPTracker);
10390b57cec5SDimitry Andric if (!BotRPTracker.getLiveThru().empty()) {
10400b57cec5SDimitry Andric TopRPTracker.initLiveThru(BotRPTracker.getLiveThru());
10410b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Live Thru: ";
10420b57cec5SDimitry Andric dumpRegSetPressure(BotRPTracker.getLiveThru(), TRI));
10430b57cec5SDimitry Andric };
10440b57cec5SDimitry Andric
10450b57cec5SDimitry Andric // For each live out vreg reduce the pressure change associated with other
10460b57cec5SDimitry Andric // uses of the same vreg below the live-out reaching def.
10470b57cec5SDimitry Andric updatePressureDiffs(RPTracker.getPressure().LiveOutRegs);
10480b57cec5SDimitry Andric
10490b57cec5SDimitry Andric // Account for liveness generated by the region boundary.
10500b57cec5SDimitry Andric if (LiveRegionEnd != RegionEnd) {
10510b57cec5SDimitry Andric SmallVector<RegisterMaskPair, 8> LiveUses;
10520b57cec5SDimitry Andric BotRPTracker.recede(&LiveUses);
10530b57cec5SDimitry Andric updatePressureDiffs(LiveUses);
10540b57cec5SDimitry Andric }
10550b57cec5SDimitry Andric
10560b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Top Pressure:\n";
10570b57cec5SDimitry Andric dumpRegSetPressure(TopRPTracker.getRegSetPressureAtPos(), TRI);
10580b57cec5SDimitry Andric dbgs() << "Bottom Pressure:\n";
10590b57cec5SDimitry Andric dumpRegSetPressure(BotRPTracker.getRegSetPressureAtPos(), TRI););
10600b57cec5SDimitry Andric
10610b57cec5SDimitry Andric assert((BotRPTracker.getPos() == RegionEnd ||
10620b57cec5SDimitry Andric (RegionEnd->isDebugInstr() &&
10630b57cec5SDimitry Andric BotRPTracker.getPos() == priorNonDebug(RegionEnd, RegionBegin))) &&
10640b57cec5SDimitry Andric "Can't find the region bottom");
10650b57cec5SDimitry Andric
10660b57cec5SDimitry Andric // Cache the list of excess pressure sets in this region. This will also track
10670b57cec5SDimitry Andric // the max pressure in the scheduled code for these sets.
10680b57cec5SDimitry Andric RegionCriticalPSets.clear();
10690b57cec5SDimitry Andric const std::vector<unsigned> &RegionPressure =
10700b57cec5SDimitry Andric RPTracker.getPressure().MaxSetPressure;
10710b57cec5SDimitry Andric for (unsigned i = 0, e = RegionPressure.size(); i < e; ++i) {
10720b57cec5SDimitry Andric unsigned Limit = RegClassInfo->getRegPressureSetLimit(i);
10730b57cec5SDimitry Andric if (RegionPressure[i] > Limit) {
10740b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << TRI->getRegPressureSetName(i) << " Limit " << Limit
10750b57cec5SDimitry Andric << " Actual " << RegionPressure[i] << "\n");
10760b57cec5SDimitry Andric RegionCriticalPSets.push_back(PressureChange(i));
10770b57cec5SDimitry Andric }
10780b57cec5SDimitry Andric }
10790b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Excess PSets: ";
10800b57cec5SDimitry Andric for (const PressureChange &RCPS
10810b57cec5SDimitry Andric : RegionCriticalPSets) dbgs()
10820b57cec5SDimitry Andric << TRI->getRegPressureSetName(RCPS.getPSet()) << " ";
10830b57cec5SDimitry Andric dbgs() << "\n");
10840b57cec5SDimitry Andric }
10850b57cec5SDimitry Andric
10860b57cec5SDimitry Andric void ScheduleDAGMILive::
updateScheduledPressure(const SUnit * SU,const std::vector<unsigned> & NewMaxPressure)10870b57cec5SDimitry Andric updateScheduledPressure(const SUnit *SU,
10880b57cec5SDimitry Andric const std::vector<unsigned> &NewMaxPressure) {
10890b57cec5SDimitry Andric const PressureDiff &PDiff = getPressureDiff(SU);
10900b57cec5SDimitry Andric unsigned CritIdx = 0, CritEnd = RegionCriticalPSets.size();
10910b57cec5SDimitry Andric for (const PressureChange &PC : PDiff) {
10920b57cec5SDimitry Andric if (!PC.isValid())
10930b57cec5SDimitry Andric break;
10940b57cec5SDimitry Andric unsigned ID = PC.getPSet();
10950b57cec5SDimitry Andric while (CritIdx != CritEnd && RegionCriticalPSets[CritIdx].getPSet() < ID)
10960b57cec5SDimitry Andric ++CritIdx;
10970b57cec5SDimitry Andric if (CritIdx != CritEnd && RegionCriticalPSets[CritIdx].getPSet() == ID) {
10980b57cec5SDimitry Andric if ((int)NewMaxPressure[ID] > RegionCriticalPSets[CritIdx].getUnitInc()
10990b57cec5SDimitry Andric && NewMaxPressure[ID] <= (unsigned)std::numeric_limits<int16_t>::max())
11000b57cec5SDimitry Andric RegionCriticalPSets[CritIdx].setUnitInc(NewMaxPressure[ID]);
11010b57cec5SDimitry Andric }
11020b57cec5SDimitry Andric unsigned Limit = RegClassInfo->getRegPressureSetLimit(ID);
11030b57cec5SDimitry Andric if (NewMaxPressure[ID] >= Limit - 2) {
11040b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " " << TRI->getRegPressureSetName(ID) << ": "
11050b57cec5SDimitry Andric << NewMaxPressure[ID]
11060b57cec5SDimitry Andric << ((NewMaxPressure[ID] > Limit) ? " > " : " <= ")
11070b57cec5SDimitry Andric << Limit << "(+ " << BotRPTracker.getLiveThru()[ID]
11080b57cec5SDimitry Andric << " livethru)\n");
11090b57cec5SDimitry Andric }
11100b57cec5SDimitry Andric }
11110b57cec5SDimitry Andric }
11120b57cec5SDimitry Andric
11130b57cec5SDimitry Andric /// Update the PressureDiff array for liveness after scheduling this
11140b57cec5SDimitry Andric /// instruction.
updatePressureDiffs(ArrayRef<RegisterMaskPair> LiveUses)11150b57cec5SDimitry Andric void ScheduleDAGMILive::updatePressureDiffs(
11160b57cec5SDimitry Andric ArrayRef<RegisterMaskPair> LiveUses) {
11170b57cec5SDimitry Andric for (const RegisterMaskPair &P : LiveUses) {
1118af732203SDimitry Andric Register Reg = P.RegUnit;
11190b57cec5SDimitry Andric /// FIXME: Currently assuming single-use physregs.
11208bcb0991SDimitry Andric if (!Register::isVirtualRegister(Reg))
11210b57cec5SDimitry Andric continue;
11220b57cec5SDimitry Andric
11230b57cec5SDimitry Andric if (ShouldTrackLaneMasks) {
11240b57cec5SDimitry Andric // If the register has just become live then other uses won't change
11250b57cec5SDimitry Andric // this fact anymore => decrement pressure.
11260b57cec5SDimitry Andric // If the register has just become dead then other uses make it come
11270b57cec5SDimitry Andric // back to life => increment pressure.
11280b57cec5SDimitry Andric bool Decrement = P.LaneMask.any();
11290b57cec5SDimitry Andric
11300b57cec5SDimitry Andric for (const VReg2SUnit &V2SU
11310b57cec5SDimitry Andric : make_range(VRegUses.find(Reg), VRegUses.end())) {
11320b57cec5SDimitry Andric SUnit &SU = *V2SU.SU;
11330b57cec5SDimitry Andric if (SU.isScheduled || &SU == &ExitSU)
11340b57cec5SDimitry Andric continue;
11350b57cec5SDimitry Andric
11360b57cec5SDimitry Andric PressureDiff &PDiff = getPressureDiff(&SU);
11370b57cec5SDimitry Andric PDiff.addPressureChange(Reg, Decrement, &MRI);
11380b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " UpdateRegP: SU(" << SU.NodeNum << ") "
11390b57cec5SDimitry Andric << printReg(Reg, TRI) << ':'
11400b57cec5SDimitry Andric << PrintLaneMask(P.LaneMask) << ' ' << *SU.getInstr();
11410b57cec5SDimitry Andric dbgs() << " to "; PDiff.dump(*TRI););
11420b57cec5SDimitry Andric }
11430b57cec5SDimitry Andric } else {
11440b57cec5SDimitry Andric assert(P.LaneMask.any());
11450b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " LiveReg: " << printVRegOrUnit(Reg, TRI) << "\n");
11460b57cec5SDimitry Andric // This may be called before CurrentBottom has been initialized. However,
11470b57cec5SDimitry Andric // BotRPTracker must have a valid position. We want the value live into the
11480b57cec5SDimitry Andric // instruction or live out of the block, so ask for the previous
11490b57cec5SDimitry Andric // instruction's live-out.
11500b57cec5SDimitry Andric const LiveInterval &LI = LIS->getInterval(Reg);
11510b57cec5SDimitry Andric VNInfo *VNI;
11520b57cec5SDimitry Andric MachineBasicBlock::const_iterator I =
11530b57cec5SDimitry Andric nextIfDebug(BotRPTracker.getPos(), BB->end());
11540b57cec5SDimitry Andric if (I == BB->end())
11550b57cec5SDimitry Andric VNI = LI.getVNInfoBefore(LIS->getMBBEndIdx(BB));
11560b57cec5SDimitry Andric else {
11570b57cec5SDimitry Andric LiveQueryResult LRQ = LI.Query(LIS->getInstructionIndex(*I));
11580b57cec5SDimitry Andric VNI = LRQ.valueIn();
11590b57cec5SDimitry Andric }
11600b57cec5SDimitry Andric // RegisterPressureTracker guarantees that readsReg is true for LiveUses.
11610b57cec5SDimitry Andric assert(VNI && "No live value at use.");
11620b57cec5SDimitry Andric for (const VReg2SUnit &V2SU
11630b57cec5SDimitry Andric : make_range(VRegUses.find(Reg), VRegUses.end())) {
11640b57cec5SDimitry Andric SUnit *SU = V2SU.SU;
11650b57cec5SDimitry Andric // If this use comes before the reaching def, it cannot be a last use,
11660b57cec5SDimitry Andric // so decrease its pressure change.
11670b57cec5SDimitry Andric if (!SU->isScheduled && SU != &ExitSU) {
11680b57cec5SDimitry Andric LiveQueryResult LRQ =
11690b57cec5SDimitry Andric LI.Query(LIS->getInstructionIndex(*SU->getInstr()));
11700b57cec5SDimitry Andric if (LRQ.valueIn() == VNI) {
11710b57cec5SDimitry Andric PressureDiff &PDiff = getPressureDiff(SU);
11720b57cec5SDimitry Andric PDiff.addPressureChange(Reg, true, &MRI);
11730b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " UpdateRegP: SU(" << SU->NodeNum << ") "
11740b57cec5SDimitry Andric << *SU->getInstr();
11750b57cec5SDimitry Andric dbgs() << " to "; PDiff.dump(*TRI););
11760b57cec5SDimitry Andric }
11770b57cec5SDimitry Andric }
11780b57cec5SDimitry Andric }
11790b57cec5SDimitry Andric }
11800b57cec5SDimitry Andric }
11810b57cec5SDimitry Andric }
11820b57cec5SDimitry Andric
dump() const11830b57cec5SDimitry Andric void ScheduleDAGMILive::dump() const {
11840b57cec5SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
11850b57cec5SDimitry Andric if (EntrySU.getInstr() != nullptr)
11860b57cec5SDimitry Andric dumpNodeAll(EntrySU);
11870b57cec5SDimitry Andric for (const SUnit &SU : SUnits) {
11880b57cec5SDimitry Andric dumpNodeAll(SU);
11890b57cec5SDimitry Andric if (ShouldTrackPressure) {
11900b57cec5SDimitry Andric dbgs() << " Pressure Diff : ";
11910b57cec5SDimitry Andric getPressureDiff(&SU).dump(*TRI);
11920b57cec5SDimitry Andric }
11930b57cec5SDimitry Andric dbgs() << " Single Issue : ";
11940b57cec5SDimitry Andric if (SchedModel.mustBeginGroup(SU.getInstr()) &&
11950b57cec5SDimitry Andric SchedModel.mustEndGroup(SU.getInstr()))
11960b57cec5SDimitry Andric dbgs() << "true;";
11970b57cec5SDimitry Andric else
11980b57cec5SDimitry Andric dbgs() << "false;";
11990b57cec5SDimitry Andric dbgs() << '\n';
12000b57cec5SDimitry Andric }
12010b57cec5SDimitry Andric if (ExitSU.getInstr() != nullptr)
12020b57cec5SDimitry Andric dumpNodeAll(ExitSU);
12030b57cec5SDimitry Andric #endif
12040b57cec5SDimitry Andric }
12050b57cec5SDimitry Andric
12060b57cec5SDimitry Andric /// schedule - Called back from MachineScheduler::runOnMachineFunction
12070b57cec5SDimitry Andric /// after setting up the current scheduling region. [RegionBegin, RegionEnd)
12080b57cec5SDimitry Andric /// only includes instructions that have DAG nodes, not scheduling boundaries.
12090b57cec5SDimitry Andric ///
12100b57cec5SDimitry Andric /// This is a skeletal driver, with all the functionality pushed into helpers,
12110b57cec5SDimitry Andric /// so that it can be easily extended by experimental schedulers. Generally,
12120b57cec5SDimitry Andric /// implementing MachineSchedStrategy should be sufficient to implement a new
12130b57cec5SDimitry Andric /// scheduling algorithm. However, if a scheduler further subclasses
12140b57cec5SDimitry Andric /// ScheduleDAGMILive then it will want to override this virtual method in order
12150b57cec5SDimitry Andric /// to update any specialized state.
schedule()12160b57cec5SDimitry Andric void ScheduleDAGMILive::schedule() {
12170b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "ScheduleDAGMILive::schedule starting\n");
12180b57cec5SDimitry Andric LLVM_DEBUG(SchedImpl->dumpPolicy());
12190b57cec5SDimitry Andric buildDAGWithRegPressure();
12200b57cec5SDimitry Andric
12210b57cec5SDimitry Andric postprocessDAG();
12220b57cec5SDimitry Andric
12230b57cec5SDimitry Andric SmallVector<SUnit*, 8> TopRoots, BotRoots;
12240b57cec5SDimitry Andric findRootsAndBiasEdges(TopRoots, BotRoots);
12250b57cec5SDimitry Andric
12260b57cec5SDimitry Andric // Initialize the strategy before modifying the DAG.
12270b57cec5SDimitry Andric // This may initialize a DFSResult to be used for queue priority.
12280b57cec5SDimitry Andric SchedImpl->initialize(this);
12290b57cec5SDimitry Andric
12300b57cec5SDimitry Andric LLVM_DEBUG(dump());
12310b57cec5SDimitry Andric if (PrintDAGs) dump();
12320b57cec5SDimitry Andric if (ViewMISchedDAGs) viewGraph();
12330b57cec5SDimitry Andric
12340b57cec5SDimitry Andric // Initialize ready queues now that the DAG and priority data are finalized.
12350b57cec5SDimitry Andric initQueues(TopRoots, BotRoots);
12360b57cec5SDimitry Andric
12370b57cec5SDimitry Andric bool IsTopNode = false;
12380b57cec5SDimitry Andric while (true) {
12390b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "** ScheduleDAGMILive::schedule picking next node\n");
12400b57cec5SDimitry Andric SUnit *SU = SchedImpl->pickNode(IsTopNode);
12410b57cec5SDimitry Andric if (!SU) break;
12420b57cec5SDimitry Andric
12430b57cec5SDimitry Andric assert(!SU->isScheduled && "Node already scheduled");
12440b57cec5SDimitry Andric if (!checkSchedLimit())
12450b57cec5SDimitry Andric break;
12460b57cec5SDimitry Andric
12470b57cec5SDimitry Andric scheduleMI(SU, IsTopNode);
12480b57cec5SDimitry Andric
12490b57cec5SDimitry Andric if (DFSResult) {
12500b57cec5SDimitry Andric unsigned SubtreeID = DFSResult->getSubtreeID(SU);
12510b57cec5SDimitry Andric if (!ScheduledTrees.test(SubtreeID)) {
12520b57cec5SDimitry Andric ScheduledTrees.set(SubtreeID);
12530b57cec5SDimitry Andric DFSResult->scheduleTree(SubtreeID);
12540b57cec5SDimitry Andric SchedImpl->scheduleTree(SubtreeID);
12550b57cec5SDimitry Andric }
12560b57cec5SDimitry Andric }
12570b57cec5SDimitry Andric
12580b57cec5SDimitry Andric // Notify the scheduling strategy after updating the DAG.
12590b57cec5SDimitry Andric SchedImpl->schedNode(SU, IsTopNode);
12600b57cec5SDimitry Andric
12610b57cec5SDimitry Andric updateQueues(SU, IsTopNode);
12620b57cec5SDimitry Andric }
12630b57cec5SDimitry Andric assert(CurrentTop == CurrentBottom && "Nonempty unscheduled zone.");
12640b57cec5SDimitry Andric
12650b57cec5SDimitry Andric placeDebugValues();
12660b57cec5SDimitry Andric
12670b57cec5SDimitry Andric LLVM_DEBUG({
12680b57cec5SDimitry Andric dbgs() << "*** Final schedule for "
12690b57cec5SDimitry Andric << printMBBReference(*begin()->getParent()) << " ***\n";
12700b57cec5SDimitry Andric dumpSchedule();
12710b57cec5SDimitry Andric dbgs() << '\n';
12720b57cec5SDimitry Andric });
12730b57cec5SDimitry Andric }
12740b57cec5SDimitry Andric
12750b57cec5SDimitry Andric /// Build the DAG and setup three register pressure trackers.
buildDAGWithRegPressure()12760b57cec5SDimitry Andric void ScheduleDAGMILive::buildDAGWithRegPressure() {
12770b57cec5SDimitry Andric if (!ShouldTrackPressure) {
12780b57cec5SDimitry Andric RPTracker.reset();
12790b57cec5SDimitry Andric RegionCriticalPSets.clear();
12800b57cec5SDimitry Andric buildSchedGraph(AA);
12810b57cec5SDimitry Andric return;
12820b57cec5SDimitry Andric }
12830b57cec5SDimitry Andric
12840b57cec5SDimitry Andric // Initialize the register pressure tracker used by buildSchedGraph.
12850b57cec5SDimitry Andric RPTracker.init(&MF, RegClassInfo, LIS, BB, LiveRegionEnd,
12860b57cec5SDimitry Andric ShouldTrackLaneMasks, /*TrackUntiedDefs=*/true);
12870b57cec5SDimitry Andric
12880b57cec5SDimitry Andric // Account for liveness generate by the region boundary.
12890b57cec5SDimitry Andric if (LiveRegionEnd != RegionEnd)
12900b57cec5SDimitry Andric RPTracker.recede();
12910b57cec5SDimitry Andric
12920b57cec5SDimitry Andric // Build the DAG, and compute current register pressure.
12930b57cec5SDimitry Andric buildSchedGraph(AA, &RPTracker, &SUPressureDiffs, LIS, ShouldTrackLaneMasks);
12940b57cec5SDimitry Andric
12950b57cec5SDimitry Andric // Initialize top/bottom trackers after computing region pressure.
12960b57cec5SDimitry Andric initRegPressure();
12970b57cec5SDimitry Andric }
12980b57cec5SDimitry Andric
computeDFSResult()12990b57cec5SDimitry Andric void ScheduleDAGMILive::computeDFSResult() {
13000b57cec5SDimitry Andric if (!DFSResult)
13010b57cec5SDimitry Andric DFSResult = new SchedDFSResult(/*BottomU*/true, MinSubtreeSize);
13020b57cec5SDimitry Andric DFSResult->clear();
13030b57cec5SDimitry Andric ScheduledTrees.clear();
13040b57cec5SDimitry Andric DFSResult->resize(SUnits.size());
13050b57cec5SDimitry Andric DFSResult->compute(SUnits);
13060b57cec5SDimitry Andric ScheduledTrees.resize(DFSResult->getNumSubtrees());
13070b57cec5SDimitry Andric }
13080b57cec5SDimitry Andric
13090b57cec5SDimitry Andric /// Compute the max cyclic critical path through the DAG. The scheduling DAG
13100b57cec5SDimitry Andric /// only provides the critical path for single block loops. To handle loops that
13110b57cec5SDimitry Andric /// span blocks, we could use the vreg path latencies provided by
13120b57cec5SDimitry Andric /// MachineTraceMetrics instead. However, MachineTraceMetrics is not currently
13130b57cec5SDimitry Andric /// available for use in the scheduler.
13140b57cec5SDimitry Andric ///
13150b57cec5SDimitry Andric /// The cyclic path estimation identifies a def-use pair that crosses the back
13160b57cec5SDimitry Andric /// edge and considers the depth and height of the nodes. For example, consider
13170b57cec5SDimitry Andric /// the following instruction sequence where each instruction has unit latency
1318af732203SDimitry Andric /// and defines an eponymous virtual register:
13190b57cec5SDimitry Andric ///
13200b57cec5SDimitry Andric /// a->b(a,c)->c(b)->d(c)->exit
13210b57cec5SDimitry Andric ///
13220b57cec5SDimitry Andric /// The cyclic critical path is a two cycles: b->c->b
13230b57cec5SDimitry Andric /// The acyclic critical path is four cycles: a->b->c->d->exit
13240b57cec5SDimitry Andric /// LiveOutHeight = height(c) = len(c->d->exit) = 2
13250b57cec5SDimitry Andric /// LiveOutDepth = depth(c) + 1 = len(a->b->c) + 1 = 3
13260b57cec5SDimitry Andric /// LiveInHeight = height(b) + 1 = len(b->c->d->exit) + 1 = 4
13270b57cec5SDimitry Andric /// LiveInDepth = depth(b) = len(a->b) = 1
13280b57cec5SDimitry Andric ///
13290b57cec5SDimitry Andric /// LiveOutDepth - LiveInDepth = 3 - 1 = 2
13300b57cec5SDimitry Andric /// LiveInHeight - LiveOutHeight = 4 - 2 = 2
13310b57cec5SDimitry Andric /// CyclicCriticalPath = min(2, 2) = 2
13320b57cec5SDimitry Andric ///
13330b57cec5SDimitry Andric /// This could be relevant to PostRA scheduling, but is currently implemented
13340b57cec5SDimitry Andric /// assuming LiveIntervals.
computeCyclicCriticalPath()13350b57cec5SDimitry Andric unsigned ScheduleDAGMILive::computeCyclicCriticalPath() {
13360b57cec5SDimitry Andric // This only applies to single block loop.
13370b57cec5SDimitry Andric if (!BB->isSuccessor(BB))
13380b57cec5SDimitry Andric return 0;
13390b57cec5SDimitry Andric
13400b57cec5SDimitry Andric unsigned MaxCyclicLatency = 0;
13410b57cec5SDimitry Andric // Visit each live out vreg def to find def/use pairs that cross iterations.
13420b57cec5SDimitry Andric for (const RegisterMaskPair &P : RPTracker.getPressure().LiveOutRegs) {
1343af732203SDimitry Andric Register Reg = P.RegUnit;
13448bcb0991SDimitry Andric if (!Register::isVirtualRegister(Reg))
13450b57cec5SDimitry Andric continue;
13460b57cec5SDimitry Andric const LiveInterval &LI = LIS->getInterval(Reg);
13470b57cec5SDimitry Andric const VNInfo *DefVNI = LI.getVNInfoBefore(LIS->getMBBEndIdx(BB));
13480b57cec5SDimitry Andric if (!DefVNI)
13490b57cec5SDimitry Andric continue;
13500b57cec5SDimitry Andric
13510b57cec5SDimitry Andric MachineInstr *DefMI = LIS->getInstructionFromIndex(DefVNI->def);
13520b57cec5SDimitry Andric const SUnit *DefSU = getSUnit(DefMI);
13530b57cec5SDimitry Andric if (!DefSU)
13540b57cec5SDimitry Andric continue;
13550b57cec5SDimitry Andric
13560b57cec5SDimitry Andric unsigned LiveOutHeight = DefSU->getHeight();
13570b57cec5SDimitry Andric unsigned LiveOutDepth = DefSU->getDepth() + DefSU->Latency;
13580b57cec5SDimitry Andric // Visit all local users of the vreg def.
13590b57cec5SDimitry Andric for (const VReg2SUnit &V2SU
13600b57cec5SDimitry Andric : make_range(VRegUses.find(Reg), VRegUses.end())) {
13610b57cec5SDimitry Andric SUnit *SU = V2SU.SU;
13620b57cec5SDimitry Andric if (SU == &ExitSU)
13630b57cec5SDimitry Andric continue;
13640b57cec5SDimitry Andric
13650b57cec5SDimitry Andric // Only consider uses of the phi.
13660b57cec5SDimitry Andric LiveQueryResult LRQ = LI.Query(LIS->getInstructionIndex(*SU->getInstr()));
13670b57cec5SDimitry Andric if (!LRQ.valueIn()->isPHIDef())
13680b57cec5SDimitry Andric continue;
13690b57cec5SDimitry Andric
13700b57cec5SDimitry Andric // Assume that a path spanning two iterations is a cycle, which could
13710b57cec5SDimitry Andric // overestimate in strange cases. This allows cyclic latency to be
13720b57cec5SDimitry Andric // estimated as the minimum slack of the vreg's depth or height.
13730b57cec5SDimitry Andric unsigned CyclicLatency = 0;
13740b57cec5SDimitry Andric if (LiveOutDepth > SU->getDepth())
13750b57cec5SDimitry Andric CyclicLatency = LiveOutDepth - SU->getDepth();
13760b57cec5SDimitry Andric
13770b57cec5SDimitry Andric unsigned LiveInHeight = SU->getHeight() + DefSU->Latency;
13780b57cec5SDimitry Andric if (LiveInHeight > LiveOutHeight) {
13790b57cec5SDimitry Andric if (LiveInHeight - LiveOutHeight < CyclicLatency)
13800b57cec5SDimitry Andric CyclicLatency = LiveInHeight - LiveOutHeight;
13810b57cec5SDimitry Andric } else
13820b57cec5SDimitry Andric CyclicLatency = 0;
13830b57cec5SDimitry Andric
13840b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Cyclic Path: SU(" << DefSU->NodeNum << ") -> SU("
13850b57cec5SDimitry Andric << SU->NodeNum << ") = " << CyclicLatency << "c\n");
13860b57cec5SDimitry Andric if (CyclicLatency > MaxCyclicLatency)
13870b57cec5SDimitry Andric MaxCyclicLatency = CyclicLatency;
13880b57cec5SDimitry Andric }
13890b57cec5SDimitry Andric }
13900b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Cyclic Critical Path: " << MaxCyclicLatency << "c\n");
13910b57cec5SDimitry Andric return MaxCyclicLatency;
13920b57cec5SDimitry Andric }
13930b57cec5SDimitry Andric
13940b57cec5SDimitry Andric /// Release ExitSU predecessors and setup scheduler queues. Re-position
13950b57cec5SDimitry Andric /// the Top RP tracker in case the region beginning has changed.
initQueues(ArrayRef<SUnit * > TopRoots,ArrayRef<SUnit * > BotRoots)13960b57cec5SDimitry Andric void ScheduleDAGMILive::initQueues(ArrayRef<SUnit*> TopRoots,
13970b57cec5SDimitry Andric ArrayRef<SUnit*> BotRoots) {
13980b57cec5SDimitry Andric ScheduleDAGMI::initQueues(TopRoots, BotRoots);
13990b57cec5SDimitry Andric if (ShouldTrackPressure) {
14000b57cec5SDimitry Andric assert(TopRPTracker.getPos() == RegionBegin && "bad initial Top tracker");
14010b57cec5SDimitry Andric TopRPTracker.setPos(CurrentTop);
14020b57cec5SDimitry Andric }
14030b57cec5SDimitry Andric }
14040b57cec5SDimitry Andric
14050b57cec5SDimitry Andric /// Move an instruction and update register pressure.
scheduleMI(SUnit * SU,bool IsTopNode)14060b57cec5SDimitry Andric void ScheduleDAGMILive::scheduleMI(SUnit *SU, bool IsTopNode) {
14070b57cec5SDimitry Andric // Move the instruction to its new location in the instruction stream.
14080b57cec5SDimitry Andric MachineInstr *MI = SU->getInstr();
14090b57cec5SDimitry Andric
14100b57cec5SDimitry Andric if (IsTopNode) {
14110b57cec5SDimitry Andric assert(SU->isTopReady() && "node still has unscheduled dependencies");
14120b57cec5SDimitry Andric if (&*CurrentTop == MI)
14130b57cec5SDimitry Andric CurrentTop = nextIfDebug(++CurrentTop, CurrentBottom);
14140b57cec5SDimitry Andric else {
14150b57cec5SDimitry Andric moveInstruction(MI, CurrentTop);
14160b57cec5SDimitry Andric TopRPTracker.setPos(MI);
14170b57cec5SDimitry Andric }
14180b57cec5SDimitry Andric
14190b57cec5SDimitry Andric if (ShouldTrackPressure) {
14200b57cec5SDimitry Andric // Update top scheduled pressure.
14210b57cec5SDimitry Andric RegisterOperands RegOpers;
14220b57cec5SDimitry Andric RegOpers.collect(*MI, *TRI, MRI, ShouldTrackLaneMasks, false);
14230b57cec5SDimitry Andric if (ShouldTrackLaneMasks) {
14240b57cec5SDimitry Andric // Adjust liveness and add missing dead+read-undef flags.
14250b57cec5SDimitry Andric SlotIndex SlotIdx = LIS->getInstructionIndex(*MI).getRegSlot();
14260b57cec5SDimitry Andric RegOpers.adjustLaneLiveness(*LIS, MRI, SlotIdx, MI);
14270b57cec5SDimitry Andric } else {
14280b57cec5SDimitry Andric // Adjust for missing dead-def flags.
14290b57cec5SDimitry Andric RegOpers.detectDeadDefs(*MI, *LIS);
14300b57cec5SDimitry Andric }
14310b57cec5SDimitry Andric
14320b57cec5SDimitry Andric TopRPTracker.advance(RegOpers);
14330b57cec5SDimitry Andric assert(TopRPTracker.getPos() == CurrentTop && "out of sync");
14340b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Top Pressure:\n"; dumpRegSetPressure(
14350b57cec5SDimitry Andric TopRPTracker.getRegSetPressureAtPos(), TRI););
14360b57cec5SDimitry Andric
14370b57cec5SDimitry Andric updateScheduledPressure(SU, TopRPTracker.getPressure().MaxSetPressure);
14380b57cec5SDimitry Andric }
14390b57cec5SDimitry Andric } else {
14400b57cec5SDimitry Andric assert(SU->isBottomReady() && "node still has unscheduled dependencies");
14410b57cec5SDimitry Andric MachineBasicBlock::iterator priorII =
14420b57cec5SDimitry Andric priorNonDebug(CurrentBottom, CurrentTop);
14430b57cec5SDimitry Andric if (&*priorII == MI)
14440b57cec5SDimitry Andric CurrentBottom = priorII;
14450b57cec5SDimitry Andric else {
14460b57cec5SDimitry Andric if (&*CurrentTop == MI) {
14470b57cec5SDimitry Andric CurrentTop = nextIfDebug(++CurrentTop, priorII);
14480b57cec5SDimitry Andric TopRPTracker.setPos(CurrentTop);
14490b57cec5SDimitry Andric }
14500b57cec5SDimitry Andric moveInstruction(MI, CurrentBottom);
14510b57cec5SDimitry Andric CurrentBottom = MI;
14520b57cec5SDimitry Andric BotRPTracker.setPos(CurrentBottom);
14530b57cec5SDimitry Andric }
14540b57cec5SDimitry Andric if (ShouldTrackPressure) {
14550b57cec5SDimitry Andric RegisterOperands RegOpers;
14560b57cec5SDimitry Andric RegOpers.collect(*MI, *TRI, MRI, ShouldTrackLaneMasks, false);
14570b57cec5SDimitry Andric if (ShouldTrackLaneMasks) {
14580b57cec5SDimitry Andric // Adjust liveness and add missing dead+read-undef flags.
14590b57cec5SDimitry Andric SlotIndex SlotIdx = LIS->getInstructionIndex(*MI).getRegSlot();
14600b57cec5SDimitry Andric RegOpers.adjustLaneLiveness(*LIS, MRI, SlotIdx, MI);
14610b57cec5SDimitry Andric } else {
14620b57cec5SDimitry Andric // Adjust for missing dead-def flags.
14630b57cec5SDimitry Andric RegOpers.detectDeadDefs(*MI, *LIS);
14640b57cec5SDimitry Andric }
14650b57cec5SDimitry Andric
14660b57cec5SDimitry Andric if (BotRPTracker.getPos() != CurrentBottom)
14670b57cec5SDimitry Andric BotRPTracker.recedeSkipDebugValues();
14680b57cec5SDimitry Andric SmallVector<RegisterMaskPair, 8> LiveUses;
14690b57cec5SDimitry Andric BotRPTracker.recede(RegOpers, &LiveUses);
14700b57cec5SDimitry Andric assert(BotRPTracker.getPos() == CurrentBottom && "out of sync");
14710b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Bottom Pressure:\n"; dumpRegSetPressure(
14720b57cec5SDimitry Andric BotRPTracker.getRegSetPressureAtPos(), TRI););
14730b57cec5SDimitry Andric
14740b57cec5SDimitry Andric updateScheduledPressure(SU, BotRPTracker.getPressure().MaxSetPressure);
14750b57cec5SDimitry Andric updatePressureDiffs(LiveUses);
14760b57cec5SDimitry Andric }
14770b57cec5SDimitry Andric }
14780b57cec5SDimitry Andric }
14790b57cec5SDimitry Andric
14800b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
14810b57cec5SDimitry Andric // BaseMemOpClusterMutation - DAG post-processing to cluster loads or stores.
14820b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
14830b57cec5SDimitry Andric
14840b57cec5SDimitry Andric namespace {
14850b57cec5SDimitry Andric
14860b57cec5SDimitry Andric /// Post-process the DAG to create cluster edges between neighboring
14870b57cec5SDimitry Andric /// loads or between neighboring stores.
14880b57cec5SDimitry Andric class BaseMemOpClusterMutation : public ScheduleDAGMutation {
14890b57cec5SDimitry Andric struct MemOpInfo {
14900b57cec5SDimitry Andric SUnit *SU;
14915ffd83dbSDimitry Andric SmallVector<const MachineOperand *, 4> BaseOps;
14920b57cec5SDimitry Andric int64_t Offset;
14935ffd83dbSDimitry Andric unsigned Width;
14940b57cec5SDimitry Andric
MemOpInfo__anonde6daefc0311::BaseMemOpClusterMutation::MemOpInfo14955ffd83dbSDimitry Andric MemOpInfo(SUnit *SU, ArrayRef<const MachineOperand *> BaseOps,
14965ffd83dbSDimitry Andric int64_t Offset, unsigned Width)
14975ffd83dbSDimitry Andric : SU(SU), BaseOps(BaseOps.begin(), BaseOps.end()), Offset(Offset),
14985ffd83dbSDimitry Andric Width(Width) {}
14990b57cec5SDimitry Andric
Compare__anonde6daefc0311::BaseMemOpClusterMutation::MemOpInfo15005ffd83dbSDimitry Andric static bool Compare(const MachineOperand *const &A,
15015ffd83dbSDimitry Andric const MachineOperand *const &B) {
15025ffd83dbSDimitry Andric if (A->getType() != B->getType())
15035ffd83dbSDimitry Andric return A->getType() < B->getType();
15045ffd83dbSDimitry Andric if (A->isReg())
15055ffd83dbSDimitry Andric return A->getReg() < B->getReg();
15065ffd83dbSDimitry Andric if (A->isFI()) {
15075ffd83dbSDimitry Andric const MachineFunction &MF = *A->getParent()->getParent()->getParent();
15080b57cec5SDimitry Andric const TargetFrameLowering &TFI = *MF.getSubtarget().getFrameLowering();
15090b57cec5SDimitry Andric bool StackGrowsDown = TFI.getStackGrowthDirection() ==
15100b57cec5SDimitry Andric TargetFrameLowering::StackGrowsDown;
15115ffd83dbSDimitry Andric return StackGrowsDown ? A->getIndex() > B->getIndex()
15125ffd83dbSDimitry Andric : A->getIndex() < B->getIndex();
15130b57cec5SDimitry Andric }
15140b57cec5SDimitry Andric
15150b57cec5SDimitry Andric llvm_unreachable("MemOpClusterMutation only supports register or frame "
15160b57cec5SDimitry Andric "index bases.");
15170b57cec5SDimitry Andric }
15185ffd83dbSDimitry Andric
operator <__anonde6daefc0311::BaseMemOpClusterMutation::MemOpInfo15195ffd83dbSDimitry Andric bool operator<(const MemOpInfo &RHS) const {
15205ffd83dbSDimitry Andric // FIXME: Don't compare everything twice. Maybe use C++20 three way
15215ffd83dbSDimitry Andric // comparison instead when it's available.
15225ffd83dbSDimitry Andric if (std::lexicographical_compare(BaseOps.begin(), BaseOps.end(),
15235ffd83dbSDimitry Andric RHS.BaseOps.begin(), RHS.BaseOps.end(),
15245ffd83dbSDimitry Andric Compare))
15255ffd83dbSDimitry Andric return true;
15265ffd83dbSDimitry Andric if (std::lexicographical_compare(RHS.BaseOps.begin(), RHS.BaseOps.end(),
15275ffd83dbSDimitry Andric BaseOps.begin(), BaseOps.end(), Compare))
15285ffd83dbSDimitry Andric return false;
15295ffd83dbSDimitry Andric if (Offset != RHS.Offset)
15305ffd83dbSDimitry Andric return Offset < RHS.Offset;
15315ffd83dbSDimitry Andric return SU->NodeNum < RHS.SU->NodeNum;
15325ffd83dbSDimitry Andric }
15330b57cec5SDimitry Andric };
15340b57cec5SDimitry Andric
15350b57cec5SDimitry Andric const TargetInstrInfo *TII;
15360b57cec5SDimitry Andric const TargetRegisterInfo *TRI;
15370b57cec5SDimitry Andric bool IsLoad;
15380b57cec5SDimitry Andric
15390b57cec5SDimitry Andric public:
BaseMemOpClusterMutation(const TargetInstrInfo * tii,const TargetRegisterInfo * tri,bool IsLoad)15400b57cec5SDimitry Andric BaseMemOpClusterMutation(const TargetInstrInfo *tii,
15410b57cec5SDimitry Andric const TargetRegisterInfo *tri, bool IsLoad)
15420b57cec5SDimitry Andric : TII(tii), TRI(tri), IsLoad(IsLoad) {}
15430b57cec5SDimitry Andric
15440b57cec5SDimitry Andric void apply(ScheduleDAGInstrs *DAGInstrs) override;
15450b57cec5SDimitry Andric
15460b57cec5SDimitry Andric protected:
1547af732203SDimitry Andric void clusterNeighboringMemOps(ArrayRef<MemOpInfo> MemOps, bool FastCluster,
1548af732203SDimitry Andric ScheduleDAGInstrs *DAG);
1549af732203SDimitry Andric void collectMemOpRecords(std::vector<SUnit> &SUnits,
1550af732203SDimitry Andric SmallVectorImpl<MemOpInfo> &MemOpRecords);
1551af732203SDimitry Andric bool groupMemOps(ArrayRef<MemOpInfo> MemOps, ScheduleDAGInstrs *DAG,
1552af732203SDimitry Andric DenseMap<unsigned, SmallVector<MemOpInfo, 32>> &Groups);
15530b57cec5SDimitry Andric };
15540b57cec5SDimitry Andric
15550b57cec5SDimitry Andric class StoreClusterMutation : public BaseMemOpClusterMutation {
15560b57cec5SDimitry Andric public:
StoreClusterMutation(const TargetInstrInfo * tii,const TargetRegisterInfo * tri)15570b57cec5SDimitry Andric StoreClusterMutation(const TargetInstrInfo *tii,
15580b57cec5SDimitry Andric const TargetRegisterInfo *tri)
15590b57cec5SDimitry Andric : BaseMemOpClusterMutation(tii, tri, false) {}
15600b57cec5SDimitry Andric };
15610b57cec5SDimitry Andric
15620b57cec5SDimitry Andric class LoadClusterMutation : public BaseMemOpClusterMutation {
15630b57cec5SDimitry Andric public:
LoadClusterMutation(const TargetInstrInfo * tii,const TargetRegisterInfo * tri)15640b57cec5SDimitry Andric LoadClusterMutation(const TargetInstrInfo *tii, const TargetRegisterInfo *tri)
15650b57cec5SDimitry Andric : BaseMemOpClusterMutation(tii, tri, true) {}
15660b57cec5SDimitry Andric };
15670b57cec5SDimitry Andric
15680b57cec5SDimitry Andric } // end anonymous namespace
15690b57cec5SDimitry Andric
15700b57cec5SDimitry Andric namespace llvm {
15710b57cec5SDimitry Andric
15720b57cec5SDimitry Andric std::unique_ptr<ScheduleDAGMutation>
createLoadClusterDAGMutation(const TargetInstrInfo * TII,const TargetRegisterInfo * TRI)15730b57cec5SDimitry Andric createLoadClusterDAGMutation(const TargetInstrInfo *TII,
15740b57cec5SDimitry Andric const TargetRegisterInfo *TRI) {
15758bcb0991SDimitry Andric return EnableMemOpCluster ? std::make_unique<LoadClusterMutation>(TII, TRI)
15760b57cec5SDimitry Andric : nullptr;
15770b57cec5SDimitry Andric }
15780b57cec5SDimitry Andric
15790b57cec5SDimitry Andric std::unique_ptr<ScheduleDAGMutation>
createStoreClusterDAGMutation(const TargetInstrInfo * TII,const TargetRegisterInfo * TRI)15800b57cec5SDimitry Andric createStoreClusterDAGMutation(const TargetInstrInfo *TII,
15810b57cec5SDimitry Andric const TargetRegisterInfo *TRI) {
15828bcb0991SDimitry Andric return EnableMemOpCluster ? std::make_unique<StoreClusterMutation>(TII, TRI)
15830b57cec5SDimitry Andric : nullptr;
15840b57cec5SDimitry Andric }
15850b57cec5SDimitry Andric
15860b57cec5SDimitry Andric } // end namespace llvm
15870b57cec5SDimitry Andric
1588af732203SDimitry Andric // Sorting all the loads/stores first, then for each load/store, checking the
1589af732203SDimitry Andric // following load/store one by one, until reach the first non-dependent one and
1590af732203SDimitry Andric // call target hook to see if they can cluster.
1591af732203SDimitry Andric // If FastCluster is enabled, we assume that, all the loads/stores have been
1592af732203SDimitry Andric // preprocessed and now, they didn't have dependencies on each other.
clusterNeighboringMemOps(ArrayRef<MemOpInfo> MemOpRecords,bool FastCluster,ScheduleDAGInstrs * DAG)15930b57cec5SDimitry Andric void BaseMemOpClusterMutation::clusterNeighboringMemOps(
1594af732203SDimitry Andric ArrayRef<MemOpInfo> MemOpRecords, bool FastCluster,
1595af732203SDimitry Andric ScheduleDAGInstrs *DAG) {
1596af732203SDimitry Andric // Keep track of the current cluster length and bytes for each SUnit.
1597af732203SDimitry Andric DenseMap<unsigned, std::pair<unsigned, unsigned>> SUnit2ClusterInfo;
15985ffd83dbSDimitry Andric
15995ffd83dbSDimitry Andric // At this point, `MemOpRecords` array must hold atleast two mem ops. Try to
16005ffd83dbSDimitry Andric // cluster mem ops collected within `MemOpRecords` array.
16010b57cec5SDimitry Andric for (unsigned Idx = 0, End = MemOpRecords.size(); Idx < (End - 1); ++Idx) {
16025ffd83dbSDimitry Andric // Decision to cluster mem ops is taken based on target dependent logic
16035ffd83dbSDimitry Andric auto MemOpa = MemOpRecords[Idx];
1604af732203SDimitry Andric
1605af732203SDimitry Andric // Seek for the next load/store to do the cluster.
1606af732203SDimitry Andric unsigned NextIdx = Idx + 1;
1607af732203SDimitry Andric for (; NextIdx < End; ++NextIdx)
1608af732203SDimitry Andric // Skip if MemOpb has been clustered already or has dependency with
1609af732203SDimitry Andric // MemOpa.
1610af732203SDimitry Andric if (!SUnit2ClusterInfo.count(MemOpRecords[NextIdx].SU->NodeNum) &&
1611af732203SDimitry Andric (FastCluster ||
1612af732203SDimitry Andric (!DAG->IsReachable(MemOpRecords[NextIdx].SU, MemOpa.SU) &&
1613af732203SDimitry Andric !DAG->IsReachable(MemOpa.SU, MemOpRecords[NextIdx].SU))))
1614af732203SDimitry Andric break;
1615af732203SDimitry Andric if (NextIdx == End)
16165ffd83dbSDimitry Andric continue;
1617af732203SDimitry Andric
1618af732203SDimitry Andric auto MemOpb = MemOpRecords[NextIdx];
1619af732203SDimitry Andric unsigned ClusterLength = 2;
1620af732203SDimitry Andric unsigned CurrentClusterBytes = MemOpa.Width + MemOpb.Width;
1621af732203SDimitry Andric if (SUnit2ClusterInfo.count(MemOpa.SU->NodeNum)) {
1622af732203SDimitry Andric ClusterLength = SUnit2ClusterInfo[MemOpa.SU->NodeNum].first + 1;
1623af732203SDimitry Andric CurrentClusterBytes =
1624af732203SDimitry Andric SUnit2ClusterInfo[MemOpa.SU->NodeNum].second + MemOpb.Width;
16255ffd83dbSDimitry Andric }
16265ffd83dbSDimitry Andric
1627af732203SDimitry Andric if (!TII->shouldClusterMemOps(MemOpa.BaseOps, MemOpb.BaseOps, ClusterLength,
1628af732203SDimitry Andric CurrentClusterBytes))
1629af732203SDimitry Andric continue;
1630af732203SDimitry Andric
16315ffd83dbSDimitry Andric SUnit *SUa = MemOpa.SU;
16325ffd83dbSDimitry Andric SUnit *SUb = MemOpb.SU;
1633480093f4SDimitry Andric if (SUa->NodeNum > SUb->NodeNum)
1634480093f4SDimitry Andric std::swap(SUa, SUb);
16355ffd83dbSDimitry Andric
16365ffd83dbSDimitry Andric // FIXME: Is this check really required?
1637af732203SDimitry Andric if (!DAG->addEdge(SUb, SDep(SUa, SDep::Cluster)))
16385ffd83dbSDimitry Andric continue;
16395ffd83dbSDimitry Andric
16400b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Cluster ld/st SU(" << SUa->NodeNum << ") - SU("
16410b57cec5SDimitry Andric << SUb->NodeNum << ")\n");
1642af732203SDimitry Andric ++NumClustered;
16435ffd83dbSDimitry Andric
1644af732203SDimitry Andric if (IsLoad) {
16450b57cec5SDimitry Andric // Copy successor edges from SUa to SUb. Interleaving computation
16460b57cec5SDimitry Andric // dependent on SUa can prevent load combining due to register reuse.
16475ffd83dbSDimitry Andric // Predecessor edges do not need to be copied from SUb to SUa since
16485ffd83dbSDimitry Andric // nearby loads should have effectively the same inputs.
16490b57cec5SDimitry Andric for (const SDep &Succ : SUa->Succs) {
16500b57cec5SDimitry Andric if (Succ.getSUnit() == SUb)
16510b57cec5SDimitry Andric continue;
16520b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " Copy Succ SU(" << Succ.getSUnit()->NodeNum
16530b57cec5SDimitry Andric << ")\n");
16540b57cec5SDimitry Andric DAG->addEdge(Succ.getSUnit(), SDep(SUb, SDep::Artificial));
16550b57cec5SDimitry Andric }
1656af732203SDimitry Andric } else {
1657af732203SDimitry Andric // Copy predecessor edges from SUb to SUa to avoid the SUnits that
1658af732203SDimitry Andric // SUb dependent on scheduled in-between SUb and SUa. Successor edges
1659af732203SDimitry Andric // do not need to be copied from SUa to SUb since no one will depend
1660af732203SDimitry Andric // on stores.
1661af732203SDimitry Andric // Notice that, we don't need to care about the memory dependency as
1662af732203SDimitry Andric // we won't try to cluster them if they have any memory dependency.
1663af732203SDimitry Andric for (const SDep &Pred : SUb->Preds) {
1664af732203SDimitry Andric if (Pred.getSUnit() == SUa)
1665af732203SDimitry Andric continue;
1666af732203SDimitry Andric LLVM_DEBUG(dbgs() << " Copy Pred SU(" << Pred.getSUnit()->NodeNum
1667af732203SDimitry Andric << ")\n");
1668af732203SDimitry Andric DAG->addEdge(SUa, SDep(Pred.getSUnit(), SDep::Artificial));
1669af732203SDimitry Andric }
1670af732203SDimitry Andric }
1671af732203SDimitry Andric
1672af732203SDimitry Andric SUnit2ClusterInfo[MemOpb.SU->NodeNum] = {ClusterLength,
1673af732203SDimitry Andric CurrentClusterBytes};
16745ffd83dbSDimitry Andric
16755ffd83dbSDimitry Andric LLVM_DEBUG(dbgs() << " Curr cluster length: " << ClusterLength
16765ffd83dbSDimitry Andric << ", Curr cluster bytes: " << CurrentClusterBytes
16775ffd83dbSDimitry Andric << "\n");
16780b57cec5SDimitry Andric }
16790b57cec5SDimitry Andric }
16800b57cec5SDimitry Andric
collectMemOpRecords(std::vector<SUnit> & SUnits,SmallVectorImpl<MemOpInfo> & MemOpRecords)1681af732203SDimitry Andric void BaseMemOpClusterMutation::collectMemOpRecords(
1682af732203SDimitry Andric std::vector<SUnit> &SUnits, SmallVectorImpl<MemOpInfo> &MemOpRecords) {
1683af732203SDimitry Andric for (auto &SU : SUnits) {
16840b57cec5SDimitry Andric if ((IsLoad && !SU.getInstr()->mayLoad()) ||
16850b57cec5SDimitry Andric (!IsLoad && !SU.getInstr()->mayStore()))
16860b57cec5SDimitry Andric continue;
16870b57cec5SDimitry Andric
1688af732203SDimitry Andric const MachineInstr &MI = *SU.getInstr();
1689af732203SDimitry Andric SmallVector<const MachineOperand *, 4> BaseOps;
1690af732203SDimitry Andric int64_t Offset;
1691af732203SDimitry Andric bool OffsetIsScalable;
1692af732203SDimitry Andric unsigned Width;
1693af732203SDimitry Andric if (TII->getMemOperandsWithOffsetWidth(MI, BaseOps, Offset,
1694af732203SDimitry Andric OffsetIsScalable, Width, TRI)) {
1695af732203SDimitry Andric MemOpRecords.push_back(MemOpInfo(&SU, BaseOps, Offset, Width));
1696af732203SDimitry Andric
1697af732203SDimitry Andric LLVM_DEBUG(dbgs() << "Num BaseOps: " << BaseOps.size() << ", Offset: "
1698af732203SDimitry Andric << Offset << ", OffsetIsScalable: " << OffsetIsScalable
1699af732203SDimitry Andric << ", Width: " << Width << "\n");
1700af732203SDimitry Andric }
1701af732203SDimitry Andric #ifndef NDEBUG
1702af732203SDimitry Andric for (auto *Op : BaseOps)
1703af732203SDimitry Andric assert(Op);
1704af732203SDimitry Andric #endif
1705af732203SDimitry Andric }
1706af732203SDimitry Andric }
1707af732203SDimitry Andric
groupMemOps(ArrayRef<MemOpInfo> MemOps,ScheduleDAGInstrs * DAG,DenseMap<unsigned,SmallVector<MemOpInfo,32>> & Groups)1708af732203SDimitry Andric bool BaseMemOpClusterMutation::groupMemOps(
1709af732203SDimitry Andric ArrayRef<MemOpInfo> MemOps, ScheduleDAGInstrs *DAG,
1710af732203SDimitry Andric DenseMap<unsigned, SmallVector<MemOpInfo, 32>> &Groups) {
1711af732203SDimitry Andric bool FastCluster =
1712af732203SDimitry Andric ForceFastCluster ||
1713af732203SDimitry Andric MemOps.size() * DAG->SUnits.size() / 1000 > FastClusterThreshold;
1714af732203SDimitry Andric
1715af732203SDimitry Andric for (const auto &MemOp : MemOps) {
17160b57cec5SDimitry Andric unsigned ChainPredID = DAG->SUnits.size();
1717af732203SDimitry Andric if (FastCluster) {
1718af732203SDimitry Andric for (const SDep &Pred : MemOp.SU->Preds) {
1719af732203SDimitry Andric // We only want to cluster the mem ops that have the same ctrl(non-data)
1720af732203SDimitry Andric // pred so that they didn't have ctrl dependency for each other. But for
1721af732203SDimitry Andric // store instrs, we can still cluster them if the pred is load instr.
1722af732203SDimitry Andric if ((Pred.isCtrl() &&
1723af732203SDimitry Andric (IsLoad ||
1724af732203SDimitry Andric (Pred.getSUnit() && Pred.getSUnit()->getInstr()->mayStore()))) &&
1725af732203SDimitry Andric !Pred.isArtificial()) {
17260b57cec5SDimitry Andric ChainPredID = Pred.getSUnit()->NodeNum;
17270b57cec5SDimitry Andric break;
17280b57cec5SDimitry Andric }
17290b57cec5SDimitry Andric }
1730af732203SDimitry Andric } else
1731af732203SDimitry Andric ChainPredID = 0;
1732af732203SDimitry Andric
1733af732203SDimitry Andric Groups[ChainPredID].push_back(MemOp);
1734af732203SDimitry Andric }
1735af732203SDimitry Andric return FastCluster;
17360b57cec5SDimitry Andric }
17370b57cec5SDimitry Andric
1738af732203SDimitry Andric /// Callback from DAG postProcessing to create cluster edges for loads/stores.
apply(ScheduleDAGInstrs * DAG)1739af732203SDimitry Andric void BaseMemOpClusterMutation::apply(ScheduleDAGInstrs *DAG) {
1740af732203SDimitry Andric // Collect all the clusterable loads/stores
1741af732203SDimitry Andric SmallVector<MemOpInfo, 32> MemOpRecords;
1742af732203SDimitry Andric collectMemOpRecords(DAG->SUnits, MemOpRecords);
1743af732203SDimitry Andric
1744af732203SDimitry Andric if (MemOpRecords.size() < 2)
1745af732203SDimitry Andric return;
1746af732203SDimitry Andric
1747af732203SDimitry Andric // Put the loads/stores without dependency into the same group with some
1748af732203SDimitry Andric // heuristic if the DAG is too complex to avoid compiling time blow up.
1749af732203SDimitry Andric // Notice that, some fusion pair could be lost with this.
1750af732203SDimitry Andric DenseMap<unsigned, SmallVector<MemOpInfo, 32>> Groups;
1751af732203SDimitry Andric bool FastCluster = groupMemOps(MemOpRecords, DAG, Groups);
1752af732203SDimitry Andric
1753af732203SDimitry Andric for (auto &Group : Groups) {
1754af732203SDimitry Andric // Sorting the loads/stores, so that, we can stop the cluster as early as
1755af732203SDimitry Andric // possible.
1756af732203SDimitry Andric llvm::sort(Group.second);
1757af732203SDimitry Andric
1758af732203SDimitry Andric // Trying to cluster all the neighboring loads/stores.
1759af732203SDimitry Andric clusterNeighboringMemOps(Group.second, FastCluster, DAG);
1760af732203SDimitry Andric }
17610b57cec5SDimitry Andric }
17620b57cec5SDimitry Andric
17630b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
17640b57cec5SDimitry Andric // CopyConstrain - DAG post-processing to encourage copy elimination.
17650b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
17660b57cec5SDimitry Andric
17670b57cec5SDimitry Andric namespace {
17680b57cec5SDimitry Andric
17690b57cec5SDimitry Andric /// Post-process the DAG to create weak edges from all uses of a copy to
17700b57cec5SDimitry Andric /// the one use that defines the copy's source vreg, most likely an induction
17710b57cec5SDimitry Andric /// variable increment.
17720b57cec5SDimitry Andric class CopyConstrain : public ScheduleDAGMutation {
17730b57cec5SDimitry Andric // Transient state.
17740b57cec5SDimitry Andric SlotIndex RegionBeginIdx;
17750b57cec5SDimitry Andric
17760b57cec5SDimitry Andric // RegionEndIdx is the slot index of the last non-debug instruction in the
17770b57cec5SDimitry Andric // scheduling region. So we may have RegionBeginIdx == RegionEndIdx.
17780b57cec5SDimitry Andric SlotIndex RegionEndIdx;
17790b57cec5SDimitry Andric
17800b57cec5SDimitry Andric public:
CopyConstrain(const TargetInstrInfo *,const TargetRegisterInfo *)17810b57cec5SDimitry Andric CopyConstrain(const TargetInstrInfo *, const TargetRegisterInfo *) {}
17820b57cec5SDimitry Andric
17830b57cec5SDimitry Andric void apply(ScheduleDAGInstrs *DAGInstrs) override;
17840b57cec5SDimitry Andric
17850b57cec5SDimitry Andric protected:
17860b57cec5SDimitry Andric void constrainLocalCopy(SUnit *CopySU, ScheduleDAGMILive *DAG);
17870b57cec5SDimitry Andric };
17880b57cec5SDimitry Andric
17890b57cec5SDimitry Andric } // end anonymous namespace
17900b57cec5SDimitry Andric
17910b57cec5SDimitry Andric namespace llvm {
17920b57cec5SDimitry Andric
17930b57cec5SDimitry Andric std::unique_ptr<ScheduleDAGMutation>
createCopyConstrainDAGMutation(const TargetInstrInfo * TII,const TargetRegisterInfo * TRI)17940b57cec5SDimitry Andric createCopyConstrainDAGMutation(const TargetInstrInfo *TII,
17950b57cec5SDimitry Andric const TargetRegisterInfo *TRI) {
17968bcb0991SDimitry Andric return std::make_unique<CopyConstrain>(TII, TRI);
17970b57cec5SDimitry Andric }
17980b57cec5SDimitry Andric
17990b57cec5SDimitry Andric } // end namespace llvm
18000b57cec5SDimitry Andric
18010b57cec5SDimitry Andric /// constrainLocalCopy handles two possibilities:
18020b57cec5SDimitry Andric /// 1) Local src:
18030b57cec5SDimitry Andric /// I0: = dst
18040b57cec5SDimitry Andric /// I1: src = ...
18050b57cec5SDimitry Andric /// I2: = dst
18060b57cec5SDimitry Andric /// I3: dst = src (copy)
18070b57cec5SDimitry Andric /// (create pred->succ edges I0->I1, I2->I1)
18080b57cec5SDimitry Andric ///
18090b57cec5SDimitry Andric /// 2) Local copy:
18100b57cec5SDimitry Andric /// I0: dst = src (copy)
18110b57cec5SDimitry Andric /// I1: = dst
18120b57cec5SDimitry Andric /// I2: src = ...
18130b57cec5SDimitry Andric /// I3: = dst
18140b57cec5SDimitry Andric /// (create pred->succ edges I1->I2, I3->I2)
18150b57cec5SDimitry Andric ///
18160b57cec5SDimitry Andric /// Although the MachineScheduler is currently constrained to single blocks,
18170b57cec5SDimitry Andric /// this algorithm should handle extended blocks. An EBB is a set of
18180b57cec5SDimitry Andric /// contiguously numbered blocks such that the previous block in the EBB is
18190b57cec5SDimitry Andric /// always the single predecessor.
constrainLocalCopy(SUnit * CopySU,ScheduleDAGMILive * DAG)18200b57cec5SDimitry Andric void CopyConstrain::constrainLocalCopy(SUnit *CopySU, ScheduleDAGMILive *DAG) {
18210b57cec5SDimitry Andric LiveIntervals *LIS = DAG->getLIS();
18220b57cec5SDimitry Andric MachineInstr *Copy = CopySU->getInstr();
18230b57cec5SDimitry Andric
18240b57cec5SDimitry Andric // Check for pure vreg copies.
18250b57cec5SDimitry Andric const MachineOperand &SrcOp = Copy->getOperand(1);
18268bcb0991SDimitry Andric Register SrcReg = SrcOp.getReg();
18278bcb0991SDimitry Andric if (!Register::isVirtualRegister(SrcReg) || !SrcOp.readsReg())
18280b57cec5SDimitry Andric return;
18290b57cec5SDimitry Andric
18300b57cec5SDimitry Andric const MachineOperand &DstOp = Copy->getOperand(0);
18318bcb0991SDimitry Andric Register DstReg = DstOp.getReg();
18328bcb0991SDimitry Andric if (!Register::isVirtualRegister(DstReg) || DstOp.isDead())
18330b57cec5SDimitry Andric return;
18340b57cec5SDimitry Andric
18350b57cec5SDimitry Andric // Check if either the dest or source is local. If it's live across a back
18360b57cec5SDimitry Andric // edge, it's not local. Note that if both vregs are live across the back
18370b57cec5SDimitry Andric // edge, we cannot successfully contrain the copy without cyclic scheduling.
18380b57cec5SDimitry Andric // If both the copy's source and dest are local live intervals, then we
18390b57cec5SDimitry Andric // should treat the dest as the global for the purpose of adding
18400b57cec5SDimitry Andric // constraints. This adds edges from source's other uses to the copy.
18410b57cec5SDimitry Andric unsigned LocalReg = SrcReg;
18420b57cec5SDimitry Andric unsigned GlobalReg = DstReg;
18430b57cec5SDimitry Andric LiveInterval *LocalLI = &LIS->getInterval(LocalReg);
18440b57cec5SDimitry Andric if (!LocalLI->isLocal(RegionBeginIdx, RegionEndIdx)) {
18450b57cec5SDimitry Andric LocalReg = DstReg;
18460b57cec5SDimitry Andric GlobalReg = SrcReg;
18470b57cec5SDimitry Andric LocalLI = &LIS->getInterval(LocalReg);
18480b57cec5SDimitry Andric if (!LocalLI->isLocal(RegionBeginIdx, RegionEndIdx))
18490b57cec5SDimitry Andric return;
18500b57cec5SDimitry Andric }
18510b57cec5SDimitry Andric LiveInterval *GlobalLI = &LIS->getInterval(GlobalReg);
18520b57cec5SDimitry Andric
18530b57cec5SDimitry Andric // Find the global segment after the start of the local LI.
18540b57cec5SDimitry Andric LiveInterval::iterator GlobalSegment = GlobalLI->find(LocalLI->beginIndex());
18550b57cec5SDimitry Andric // If GlobalLI does not overlap LocalLI->start, then a copy directly feeds a
18560b57cec5SDimitry Andric // local live range. We could create edges from other global uses to the local
18570b57cec5SDimitry Andric // start, but the coalescer should have already eliminated these cases, so
18580b57cec5SDimitry Andric // don't bother dealing with it.
18590b57cec5SDimitry Andric if (GlobalSegment == GlobalLI->end())
18600b57cec5SDimitry Andric return;
18610b57cec5SDimitry Andric
18620b57cec5SDimitry Andric // If GlobalSegment is killed at the LocalLI->start, the call to find()
18630b57cec5SDimitry Andric // returned the next global segment. But if GlobalSegment overlaps with
18640b57cec5SDimitry Andric // LocalLI->start, then advance to the next segment. If a hole in GlobalLI
18650b57cec5SDimitry Andric // exists in LocalLI's vicinity, GlobalSegment will be the end of the hole.
18660b57cec5SDimitry Andric if (GlobalSegment->contains(LocalLI->beginIndex()))
18670b57cec5SDimitry Andric ++GlobalSegment;
18680b57cec5SDimitry Andric
18690b57cec5SDimitry Andric if (GlobalSegment == GlobalLI->end())
18700b57cec5SDimitry Andric return;
18710b57cec5SDimitry Andric
18720b57cec5SDimitry Andric // Check if GlobalLI contains a hole in the vicinity of LocalLI.
18730b57cec5SDimitry Andric if (GlobalSegment != GlobalLI->begin()) {
18740b57cec5SDimitry Andric // Two address defs have no hole.
18750b57cec5SDimitry Andric if (SlotIndex::isSameInstr(std::prev(GlobalSegment)->end,
18760b57cec5SDimitry Andric GlobalSegment->start)) {
18770b57cec5SDimitry Andric return;
18780b57cec5SDimitry Andric }
18790b57cec5SDimitry Andric // If the prior global segment may be defined by the same two-address
18800b57cec5SDimitry Andric // instruction that also defines LocalLI, then can't make a hole here.
18810b57cec5SDimitry Andric if (SlotIndex::isSameInstr(std::prev(GlobalSegment)->start,
18820b57cec5SDimitry Andric LocalLI->beginIndex())) {
18830b57cec5SDimitry Andric return;
18840b57cec5SDimitry Andric }
18850b57cec5SDimitry Andric // If GlobalLI has a prior segment, it must be live into the EBB. Otherwise
18860b57cec5SDimitry Andric // it would be a disconnected component in the live range.
18870b57cec5SDimitry Andric assert(std::prev(GlobalSegment)->start < LocalLI->beginIndex() &&
18880b57cec5SDimitry Andric "Disconnected LRG within the scheduling region.");
18890b57cec5SDimitry Andric }
18900b57cec5SDimitry Andric MachineInstr *GlobalDef = LIS->getInstructionFromIndex(GlobalSegment->start);
18910b57cec5SDimitry Andric if (!GlobalDef)
18920b57cec5SDimitry Andric return;
18930b57cec5SDimitry Andric
18940b57cec5SDimitry Andric SUnit *GlobalSU = DAG->getSUnit(GlobalDef);
18950b57cec5SDimitry Andric if (!GlobalSU)
18960b57cec5SDimitry Andric return;
18970b57cec5SDimitry Andric
18980b57cec5SDimitry Andric // GlobalDef is the bottom of the GlobalLI hole. Open the hole by
18990b57cec5SDimitry Andric // constraining the uses of the last local def to precede GlobalDef.
19000b57cec5SDimitry Andric SmallVector<SUnit*,8> LocalUses;
19010b57cec5SDimitry Andric const VNInfo *LastLocalVN = LocalLI->getVNInfoBefore(LocalLI->endIndex());
19020b57cec5SDimitry Andric MachineInstr *LastLocalDef = LIS->getInstructionFromIndex(LastLocalVN->def);
19030b57cec5SDimitry Andric SUnit *LastLocalSU = DAG->getSUnit(LastLocalDef);
19040b57cec5SDimitry Andric for (const SDep &Succ : LastLocalSU->Succs) {
19050b57cec5SDimitry Andric if (Succ.getKind() != SDep::Data || Succ.getReg() != LocalReg)
19060b57cec5SDimitry Andric continue;
19070b57cec5SDimitry Andric if (Succ.getSUnit() == GlobalSU)
19080b57cec5SDimitry Andric continue;
19090b57cec5SDimitry Andric if (!DAG->canAddEdge(GlobalSU, Succ.getSUnit()))
19100b57cec5SDimitry Andric return;
19110b57cec5SDimitry Andric LocalUses.push_back(Succ.getSUnit());
19120b57cec5SDimitry Andric }
19130b57cec5SDimitry Andric // Open the top of the GlobalLI hole by constraining any earlier global uses
19140b57cec5SDimitry Andric // to precede the start of LocalLI.
19150b57cec5SDimitry Andric SmallVector<SUnit*,8> GlobalUses;
19160b57cec5SDimitry Andric MachineInstr *FirstLocalDef =
19170b57cec5SDimitry Andric LIS->getInstructionFromIndex(LocalLI->beginIndex());
19180b57cec5SDimitry Andric SUnit *FirstLocalSU = DAG->getSUnit(FirstLocalDef);
19190b57cec5SDimitry Andric for (const SDep &Pred : GlobalSU->Preds) {
19200b57cec5SDimitry Andric if (Pred.getKind() != SDep::Anti || Pred.getReg() != GlobalReg)
19210b57cec5SDimitry Andric continue;
19220b57cec5SDimitry Andric if (Pred.getSUnit() == FirstLocalSU)
19230b57cec5SDimitry Andric continue;
19240b57cec5SDimitry Andric if (!DAG->canAddEdge(FirstLocalSU, Pred.getSUnit()))
19250b57cec5SDimitry Andric return;
19260b57cec5SDimitry Andric GlobalUses.push_back(Pred.getSUnit());
19270b57cec5SDimitry Andric }
19280b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Constraining copy SU(" << CopySU->NodeNum << ")\n");
19290b57cec5SDimitry Andric // Add the weak edges.
1930*5f7ddb14SDimitry Andric for (SUnit *LU : LocalUses) {
1931*5f7ddb14SDimitry Andric LLVM_DEBUG(dbgs() << " Local use SU(" << LU->NodeNum << ") -> SU("
19320b57cec5SDimitry Andric << GlobalSU->NodeNum << ")\n");
1933*5f7ddb14SDimitry Andric DAG->addEdge(GlobalSU, SDep(LU, SDep::Weak));
19340b57cec5SDimitry Andric }
1935*5f7ddb14SDimitry Andric for (SUnit *GU : GlobalUses) {
1936*5f7ddb14SDimitry Andric LLVM_DEBUG(dbgs() << " Global use SU(" << GU->NodeNum << ") -> SU("
19370b57cec5SDimitry Andric << FirstLocalSU->NodeNum << ")\n");
1938*5f7ddb14SDimitry Andric DAG->addEdge(FirstLocalSU, SDep(GU, SDep::Weak));
19390b57cec5SDimitry Andric }
19400b57cec5SDimitry Andric }
19410b57cec5SDimitry Andric
19420b57cec5SDimitry Andric /// Callback from DAG postProcessing to create weak edges to encourage
19430b57cec5SDimitry Andric /// copy elimination.
apply(ScheduleDAGInstrs * DAGInstrs)19440b57cec5SDimitry Andric void CopyConstrain::apply(ScheduleDAGInstrs *DAGInstrs) {
19450b57cec5SDimitry Andric ScheduleDAGMI *DAG = static_cast<ScheduleDAGMI*>(DAGInstrs);
19460b57cec5SDimitry Andric assert(DAG->hasVRegLiveness() && "Expect VRegs with LiveIntervals");
19470b57cec5SDimitry Andric
19480b57cec5SDimitry Andric MachineBasicBlock::iterator FirstPos = nextIfDebug(DAG->begin(), DAG->end());
19490b57cec5SDimitry Andric if (FirstPos == DAG->end())
19500b57cec5SDimitry Andric return;
19510b57cec5SDimitry Andric RegionBeginIdx = DAG->getLIS()->getInstructionIndex(*FirstPos);
19520b57cec5SDimitry Andric RegionEndIdx = DAG->getLIS()->getInstructionIndex(
19530b57cec5SDimitry Andric *priorNonDebug(DAG->end(), DAG->begin()));
19540b57cec5SDimitry Andric
19550b57cec5SDimitry Andric for (SUnit &SU : DAG->SUnits) {
19560b57cec5SDimitry Andric if (!SU.getInstr()->isCopy())
19570b57cec5SDimitry Andric continue;
19580b57cec5SDimitry Andric
19590b57cec5SDimitry Andric constrainLocalCopy(&SU, static_cast<ScheduleDAGMILive*>(DAG));
19600b57cec5SDimitry Andric }
19610b57cec5SDimitry Andric }
19620b57cec5SDimitry Andric
19630b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
19640b57cec5SDimitry Andric // MachineSchedStrategy helpers used by GenericScheduler, GenericPostScheduler
19650b57cec5SDimitry Andric // and possibly other custom schedulers.
19660b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
19670b57cec5SDimitry Andric
19680b57cec5SDimitry Andric static const unsigned InvalidCycle = ~0U;
19690b57cec5SDimitry Andric
~SchedBoundary()19700b57cec5SDimitry Andric SchedBoundary::~SchedBoundary() { delete HazardRec; }
19710b57cec5SDimitry Andric
19720b57cec5SDimitry Andric /// Given a Count of resource usage and a Latency value, return true if a
19730b57cec5SDimitry Andric /// SchedBoundary becomes resource limited.
19740b57cec5SDimitry Andric /// If we are checking after scheduling a node, we should return true when
19750b57cec5SDimitry Andric /// we just reach the resource limit.
checkResourceLimit(unsigned LFactor,unsigned Count,unsigned Latency,bool AfterSchedNode)19760b57cec5SDimitry Andric static bool checkResourceLimit(unsigned LFactor, unsigned Count,
19770b57cec5SDimitry Andric unsigned Latency, bool AfterSchedNode) {
19780b57cec5SDimitry Andric int ResCntFactor = (int)(Count - (Latency * LFactor));
19790b57cec5SDimitry Andric if (AfterSchedNode)
19800b57cec5SDimitry Andric return ResCntFactor >= (int)LFactor;
19810b57cec5SDimitry Andric else
19820b57cec5SDimitry Andric return ResCntFactor > (int)LFactor;
19830b57cec5SDimitry Andric }
19840b57cec5SDimitry Andric
reset()19850b57cec5SDimitry Andric void SchedBoundary::reset() {
19860b57cec5SDimitry Andric // A new HazardRec is created for each DAG and owned by SchedBoundary.
19870b57cec5SDimitry Andric // Destroying and reconstructing it is very expensive though. So keep
19880b57cec5SDimitry Andric // invalid, placeholder HazardRecs.
19890b57cec5SDimitry Andric if (HazardRec && HazardRec->isEnabled()) {
19900b57cec5SDimitry Andric delete HazardRec;
19910b57cec5SDimitry Andric HazardRec = nullptr;
19920b57cec5SDimitry Andric }
19930b57cec5SDimitry Andric Available.clear();
19940b57cec5SDimitry Andric Pending.clear();
19950b57cec5SDimitry Andric CheckPending = false;
19960b57cec5SDimitry Andric CurrCycle = 0;
19970b57cec5SDimitry Andric CurrMOps = 0;
19980b57cec5SDimitry Andric MinReadyCycle = std::numeric_limits<unsigned>::max();
19990b57cec5SDimitry Andric ExpectedLatency = 0;
20000b57cec5SDimitry Andric DependentLatency = 0;
20010b57cec5SDimitry Andric RetiredMOps = 0;
20020b57cec5SDimitry Andric MaxExecutedResCount = 0;
20030b57cec5SDimitry Andric ZoneCritResIdx = 0;
20040b57cec5SDimitry Andric IsResourceLimited = false;
20050b57cec5SDimitry Andric ReservedCycles.clear();
20060b57cec5SDimitry Andric ReservedCyclesIndex.clear();
2007*5f7ddb14SDimitry Andric ResourceGroupSubUnitMasks.clear();
20080b57cec5SDimitry Andric #ifndef NDEBUG
20090b57cec5SDimitry Andric // Track the maximum number of stall cycles that could arise either from the
20100b57cec5SDimitry Andric // latency of a DAG edge or the number of cycles that a processor resource is
20110b57cec5SDimitry Andric // reserved (SchedBoundary::ReservedCycles).
20120b57cec5SDimitry Andric MaxObservedStall = 0;
20130b57cec5SDimitry Andric #endif
20140b57cec5SDimitry Andric // Reserve a zero-count for invalid CritResIdx.
20150b57cec5SDimitry Andric ExecutedResCounts.resize(1);
20160b57cec5SDimitry Andric assert(!ExecutedResCounts[0] && "nonzero count for bad resource");
20170b57cec5SDimitry Andric }
20180b57cec5SDimitry Andric
20190b57cec5SDimitry Andric void SchedRemainder::
init(ScheduleDAGMI * DAG,const TargetSchedModel * SchedModel)20200b57cec5SDimitry Andric init(ScheduleDAGMI *DAG, const TargetSchedModel *SchedModel) {
20210b57cec5SDimitry Andric reset();
20220b57cec5SDimitry Andric if (!SchedModel->hasInstrSchedModel())
20230b57cec5SDimitry Andric return;
20240b57cec5SDimitry Andric RemainingCounts.resize(SchedModel->getNumProcResourceKinds());
20250b57cec5SDimitry Andric for (SUnit &SU : DAG->SUnits) {
20260b57cec5SDimitry Andric const MCSchedClassDesc *SC = DAG->getSchedClass(&SU);
20270b57cec5SDimitry Andric RemIssueCount += SchedModel->getNumMicroOps(SU.getInstr(), SC)
20280b57cec5SDimitry Andric * SchedModel->getMicroOpFactor();
20290b57cec5SDimitry Andric for (TargetSchedModel::ProcResIter
20300b57cec5SDimitry Andric PI = SchedModel->getWriteProcResBegin(SC),
20310b57cec5SDimitry Andric PE = SchedModel->getWriteProcResEnd(SC); PI != PE; ++PI) {
20320b57cec5SDimitry Andric unsigned PIdx = PI->ProcResourceIdx;
20330b57cec5SDimitry Andric unsigned Factor = SchedModel->getResourceFactor(PIdx);
20340b57cec5SDimitry Andric RemainingCounts[PIdx] += (Factor * PI->Cycles);
20350b57cec5SDimitry Andric }
20360b57cec5SDimitry Andric }
20370b57cec5SDimitry Andric }
20380b57cec5SDimitry Andric
20390b57cec5SDimitry Andric void SchedBoundary::
init(ScheduleDAGMI * dag,const TargetSchedModel * smodel,SchedRemainder * rem)20400b57cec5SDimitry Andric init(ScheduleDAGMI *dag, const TargetSchedModel *smodel, SchedRemainder *rem) {
20410b57cec5SDimitry Andric reset();
20420b57cec5SDimitry Andric DAG = dag;
20430b57cec5SDimitry Andric SchedModel = smodel;
20440b57cec5SDimitry Andric Rem = rem;
20450b57cec5SDimitry Andric if (SchedModel->hasInstrSchedModel()) {
20460b57cec5SDimitry Andric unsigned ResourceCount = SchedModel->getNumProcResourceKinds();
20470b57cec5SDimitry Andric ReservedCyclesIndex.resize(ResourceCount);
20480b57cec5SDimitry Andric ExecutedResCounts.resize(ResourceCount);
2049*5f7ddb14SDimitry Andric ResourceGroupSubUnitMasks.resize(ResourceCount, APInt(ResourceCount, 0));
20500b57cec5SDimitry Andric unsigned NumUnits = 0;
20510b57cec5SDimitry Andric
20520b57cec5SDimitry Andric for (unsigned i = 0; i < ResourceCount; ++i) {
20530b57cec5SDimitry Andric ReservedCyclesIndex[i] = NumUnits;
20540b57cec5SDimitry Andric NumUnits += SchedModel->getProcResource(i)->NumUnits;
2055*5f7ddb14SDimitry Andric if (isUnbufferedGroup(i)) {
2056*5f7ddb14SDimitry Andric auto SubUnits = SchedModel->getProcResource(i)->SubUnitsIdxBegin;
2057*5f7ddb14SDimitry Andric for (unsigned U = 0, UE = SchedModel->getProcResource(i)->NumUnits;
2058*5f7ddb14SDimitry Andric U != UE; ++U)
2059*5f7ddb14SDimitry Andric ResourceGroupSubUnitMasks[i].setBit(SubUnits[U]);
2060*5f7ddb14SDimitry Andric }
20610b57cec5SDimitry Andric }
20620b57cec5SDimitry Andric
20630b57cec5SDimitry Andric ReservedCycles.resize(NumUnits, InvalidCycle);
20640b57cec5SDimitry Andric }
20650b57cec5SDimitry Andric }
20660b57cec5SDimitry Andric
20670b57cec5SDimitry Andric /// Compute the stall cycles based on this SUnit's ready time. Heuristics treat
20680b57cec5SDimitry Andric /// these "soft stalls" differently than the hard stall cycles based on CPU
20690b57cec5SDimitry Andric /// resources and computed by checkHazard(). A fully in-order model
20700b57cec5SDimitry Andric /// (MicroOpBufferSize==0) will not make use of this since instructions are not
20710b57cec5SDimitry Andric /// available for scheduling until they are ready. However, a weaker in-order
20720b57cec5SDimitry Andric /// model may use this for heuristics. For example, if a processor has in-order
20730b57cec5SDimitry Andric /// behavior when reading certain resources, this may come into play.
getLatencyStallCycles(SUnit * SU)20740b57cec5SDimitry Andric unsigned SchedBoundary::getLatencyStallCycles(SUnit *SU) {
20750b57cec5SDimitry Andric if (!SU->isUnbuffered)
20760b57cec5SDimitry Andric return 0;
20770b57cec5SDimitry Andric
20780b57cec5SDimitry Andric unsigned ReadyCycle = (isTop() ? SU->TopReadyCycle : SU->BotReadyCycle);
20790b57cec5SDimitry Andric if (ReadyCycle > CurrCycle)
20800b57cec5SDimitry Andric return ReadyCycle - CurrCycle;
20810b57cec5SDimitry Andric return 0;
20820b57cec5SDimitry Andric }
20830b57cec5SDimitry Andric
20840b57cec5SDimitry Andric /// Compute the next cycle at which the given processor resource unit
20850b57cec5SDimitry Andric /// can be scheduled.
getNextResourceCycleByInstance(unsigned InstanceIdx,unsigned Cycles)20860b57cec5SDimitry Andric unsigned SchedBoundary::getNextResourceCycleByInstance(unsigned InstanceIdx,
20870b57cec5SDimitry Andric unsigned Cycles) {
20880b57cec5SDimitry Andric unsigned NextUnreserved = ReservedCycles[InstanceIdx];
20890b57cec5SDimitry Andric // If this resource has never been used, always return cycle zero.
20900b57cec5SDimitry Andric if (NextUnreserved == InvalidCycle)
20910b57cec5SDimitry Andric return 0;
20920b57cec5SDimitry Andric // For bottom-up scheduling add the cycles needed for the current operation.
20930b57cec5SDimitry Andric if (!isTop())
20940b57cec5SDimitry Andric NextUnreserved += Cycles;
20950b57cec5SDimitry Andric return NextUnreserved;
20960b57cec5SDimitry Andric }
20970b57cec5SDimitry Andric
20980b57cec5SDimitry Andric /// Compute the next cycle at which the given processor resource can be
20990b57cec5SDimitry Andric /// scheduled. Returns the next cycle and the index of the processor resource
21000b57cec5SDimitry Andric /// instance in the reserved cycles vector.
21010b57cec5SDimitry Andric std::pair<unsigned, unsigned>
getNextResourceCycle(const MCSchedClassDesc * SC,unsigned PIdx,unsigned Cycles)2102*5f7ddb14SDimitry Andric SchedBoundary::getNextResourceCycle(const MCSchedClassDesc *SC, unsigned PIdx,
2103*5f7ddb14SDimitry Andric unsigned Cycles) {
2104*5f7ddb14SDimitry Andric
21050b57cec5SDimitry Andric unsigned MinNextUnreserved = InvalidCycle;
21060b57cec5SDimitry Andric unsigned InstanceIdx = 0;
21070b57cec5SDimitry Andric unsigned StartIndex = ReservedCyclesIndex[PIdx];
21080b57cec5SDimitry Andric unsigned NumberOfInstances = SchedModel->getProcResource(PIdx)->NumUnits;
21090b57cec5SDimitry Andric assert(NumberOfInstances > 0 &&
21100b57cec5SDimitry Andric "Cannot have zero instances of a ProcResource");
21110b57cec5SDimitry Andric
2112*5f7ddb14SDimitry Andric if (isUnbufferedGroup(PIdx)) {
2113*5f7ddb14SDimitry Andric // If any subunits are used by the instruction, report that the resource
2114*5f7ddb14SDimitry Andric // group is available at 0, effectively removing the group record from
2115*5f7ddb14SDimitry Andric // hazarding and basing the hazarding decisions on the subunit records.
2116*5f7ddb14SDimitry Andric // Otherwise, choose the first available instance from among the subunits.
2117*5f7ddb14SDimitry Andric // Specifications which assign cycles to both the subunits and the group or
2118*5f7ddb14SDimitry Andric // which use an unbuffered group with buffered subunits will appear to
2119*5f7ddb14SDimitry Andric // schedule strangely. In the first case, the additional cycles for the
2120*5f7ddb14SDimitry Andric // group will be ignored. In the second, the group will be ignored
2121*5f7ddb14SDimitry Andric // entirely.
2122*5f7ddb14SDimitry Andric for (const MCWriteProcResEntry &PE :
2123*5f7ddb14SDimitry Andric make_range(SchedModel->getWriteProcResBegin(SC),
2124*5f7ddb14SDimitry Andric SchedModel->getWriteProcResEnd(SC)))
2125*5f7ddb14SDimitry Andric if (ResourceGroupSubUnitMasks[PIdx][PE.ProcResourceIdx])
2126*5f7ddb14SDimitry Andric return std::make_pair(0u, StartIndex);
2127*5f7ddb14SDimitry Andric
2128*5f7ddb14SDimitry Andric auto SubUnits = SchedModel->getProcResource(PIdx)->SubUnitsIdxBegin;
2129*5f7ddb14SDimitry Andric for (unsigned I = 0, End = NumberOfInstances; I < End; ++I) {
2130*5f7ddb14SDimitry Andric unsigned NextUnreserved, NextInstanceIdx;
2131*5f7ddb14SDimitry Andric std::tie(NextUnreserved, NextInstanceIdx) =
2132*5f7ddb14SDimitry Andric getNextResourceCycle(SC, SubUnits[I], Cycles);
2133*5f7ddb14SDimitry Andric if (MinNextUnreserved > NextUnreserved) {
2134*5f7ddb14SDimitry Andric InstanceIdx = NextInstanceIdx;
2135*5f7ddb14SDimitry Andric MinNextUnreserved = NextUnreserved;
2136*5f7ddb14SDimitry Andric }
2137*5f7ddb14SDimitry Andric }
2138*5f7ddb14SDimitry Andric return std::make_pair(MinNextUnreserved, InstanceIdx);
2139*5f7ddb14SDimitry Andric }
2140*5f7ddb14SDimitry Andric
21410b57cec5SDimitry Andric for (unsigned I = StartIndex, End = StartIndex + NumberOfInstances; I < End;
21420b57cec5SDimitry Andric ++I) {
21430b57cec5SDimitry Andric unsigned NextUnreserved = getNextResourceCycleByInstance(I, Cycles);
21440b57cec5SDimitry Andric if (MinNextUnreserved > NextUnreserved) {
21450b57cec5SDimitry Andric InstanceIdx = I;
21460b57cec5SDimitry Andric MinNextUnreserved = NextUnreserved;
21470b57cec5SDimitry Andric }
21480b57cec5SDimitry Andric }
21490b57cec5SDimitry Andric return std::make_pair(MinNextUnreserved, InstanceIdx);
21500b57cec5SDimitry Andric }
21510b57cec5SDimitry Andric
21520b57cec5SDimitry Andric /// Does this SU have a hazard within the current instruction group.
21530b57cec5SDimitry Andric ///
21540b57cec5SDimitry Andric /// The scheduler supports two modes of hazard recognition. The first is the
21550b57cec5SDimitry Andric /// ScheduleHazardRecognizer API. It is a fully general hazard recognizer that
21560b57cec5SDimitry Andric /// supports highly complicated in-order reservation tables
21570b57cec5SDimitry Andric /// (ScoreboardHazardRecognizer) and arbitrary target-specific logic.
21580b57cec5SDimitry Andric ///
21590b57cec5SDimitry Andric /// The second is a streamlined mechanism that checks for hazards based on
21600b57cec5SDimitry Andric /// simple counters that the scheduler itself maintains. It explicitly checks
21610b57cec5SDimitry Andric /// for instruction dispatch limitations, including the number of micro-ops that
21620b57cec5SDimitry Andric /// can dispatch per cycle.
21630b57cec5SDimitry Andric ///
21640b57cec5SDimitry Andric /// TODO: Also check whether the SU must start a new group.
checkHazard(SUnit * SU)21650b57cec5SDimitry Andric bool SchedBoundary::checkHazard(SUnit *SU) {
21660b57cec5SDimitry Andric if (HazardRec->isEnabled()
21670b57cec5SDimitry Andric && HazardRec->getHazardType(SU) != ScheduleHazardRecognizer::NoHazard) {
21680b57cec5SDimitry Andric return true;
21690b57cec5SDimitry Andric }
21700b57cec5SDimitry Andric
21710b57cec5SDimitry Andric unsigned uops = SchedModel->getNumMicroOps(SU->getInstr());
21720b57cec5SDimitry Andric if ((CurrMOps > 0) && (CurrMOps + uops > SchedModel->getIssueWidth())) {
21730b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " SU(" << SU->NodeNum << ") uops="
21740b57cec5SDimitry Andric << SchedModel->getNumMicroOps(SU->getInstr()) << '\n');
21750b57cec5SDimitry Andric return true;
21760b57cec5SDimitry Andric }
21770b57cec5SDimitry Andric
21780b57cec5SDimitry Andric if (CurrMOps > 0 &&
21790b57cec5SDimitry Andric ((isTop() && SchedModel->mustBeginGroup(SU->getInstr())) ||
21800b57cec5SDimitry Andric (!isTop() && SchedModel->mustEndGroup(SU->getInstr())))) {
21810b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " hazard: SU(" << SU->NodeNum << ") must "
21820b57cec5SDimitry Andric << (isTop() ? "begin" : "end") << " group\n");
21830b57cec5SDimitry Andric return true;
21840b57cec5SDimitry Andric }
21850b57cec5SDimitry Andric
21860b57cec5SDimitry Andric if (SchedModel->hasInstrSchedModel() && SU->hasReservedResource) {
21870b57cec5SDimitry Andric const MCSchedClassDesc *SC = DAG->getSchedClass(SU);
21880b57cec5SDimitry Andric for (const MCWriteProcResEntry &PE :
21890b57cec5SDimitry Andric make_range(SchedModel->getWriteProcResBegin(SC),
21900b57cec5SDimitry Andric SchedModel->getWriteProcResEnd(SC))) {
21910b57cec5SDimitry Andric unsigned ResIdx = PE.ProcResourceIdx;
21920b57cec5SDimitry Andric unsigned Cycles = PE.Cycles;
21930b57cec5SDimitry Andric unsigned NRCycle, InstanceIdx;
2194*5f7ddb14SDimitry Andric std::tie(NRCycle, InstanceIdx) = getNextResourceCycle(SC, ResIdx, Cycles);
21950b57cec5SDimitry Andric if (NRCycle > CurrCycle) {
21960b57cec5SDimitry Andric #ifndef NDEBUG
21970b57cec5SDimitry Andric MaxObservedStall = std::max(Cycles, MaxObservedStall);
21980b57cec5SDimitry Andric #endif
21990b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " SU(" << SU->NodeNum << ") "
22000b57cec5SDimitry Andric << SchedModel->getResourceName(ResIdx)
22010b57cec5SDimitry Andric << '[' << InstanceIdx - ReservedCyclesIndex[ResIdx] << ']'
22020b57cec5SDimitry Andric << "=" << NRCycle << "c\n");
22030b57cec5SDimitry Andric return true;
22040b57cec5SDimitry Andric }
22050b57cec5SDimitry Andric }
22060b57cec5SDimitry Andric }
22070b57cec5SDimitry Andric return false;
22080b57cec5SDimitry Andric }
22090b57cec5SDimitry Andric
22100b57cec5SDimitry Andric // Find the unscheduled node in ReadySUs with the highest latency.
22110b57cec5SDimitry Andric unsigned SchedBoundary::
findMaxLatency(ArrayRef<SUnit * > ReadySUs)22120b57cec5SDimitry Andric findMaxLatency(ArrayRef<SUnit*> ReadySUs) {
22130b57cec5SDimitry Andric SUnit *LateSU = nullptr;
22140b57cec5SDimitry Andric unsigned RemLatency = 0;
22150b57cec5SDimitry Andric for (SUnit *SU : ReadySUs) {
22160b57cec5SDimitry Andric unsigned L = getUnscheduledLatency(SU);
22170b57cec5SDimitry Andric if (L > RemLatency) {
22180b57cec5SDimitry Andric RemLatency = L;
22190b57cec5SDimitry Andric LateSU = SU;
22200b57cec5SDimitry Andric }
22210b57cec5SDimitry Andric }
22220b57cec5SDimitry Andric if (LateSU) {
22230b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << Available.getName() << " RemLatency SU("
22240b57cec5SDimitry Andric << LateSU->NodeNum << ") " << RemLatency << "c\n");
22250b57cec5SDimitry Andric }
22260b57cec5SDimitry Andric return RemLatency;
22270b57cec5SDimitry Andric }
22280b57cec5SDimitry Andric
22290b57cec5SDimitry Andric // Count resources in this zone and the remaining unscheduled
22300b57cec5SDimitry Andric // instruction. Return the max count, scaled. Set OtherCritIdx to the critical
22310b57cec5SDimitry Andric // resource index, or zero if the zone is issue limited.
22320b57cec5SDimitry Andric unsigned SchedBoundary::
getOtherResourceCount(unsigned & OtherCritIdx)22330b57cec5SDimitry Andric getOtherResourceCount(unsigned &OtherCritIdx) {
22340b57cec5SDimitry Andric OtherCritIdx = 0;
22350b57cec5SDimitry Andric if (!SchedModel->hasInstrSchedModel())
22360b57cec5SDimitry Andric return 0;
22370b57cec5SDimitry Andric
22380b57cec5SDimitry Andric unsigned OtherCritCount = Rem->RemIssueCount
22390b57cec5SDimitry Andric + (RetiredMOps * SchedModel->getMicroOpFactor());
22400b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " " << Available.getName() << " + Remain MOps: "
22410b57cec5SDimitry Andric << OtherCritCount / SchedModel->getMicroOpFactor() << '\n');
22420b57cec5SDimitry Andric for (unsigned PIdx = 1, PEnd = SchedModel->getNumProcResourceKinds();
22430b57cec5SDimitry Andric PIdx != PEnd; ++PIdx) {
22440b57cec5SDimitry Andric unsigned OtherCount = getResourceCount(PIdx) + Rem->RemainingCounts[PIdx];
22450b57cec5SDimitry Andric if (OtherCount > OtherCritCount) {
22460b57cec5SDimitry Andric OtherCritCount = OtherCount;
22470b57cec5SDimitry Andric OtherCritIdx = PIdx;
22480b57cec5SDimitry Andric }
22490b57cec5SDimitry Andric }
22500b57cec5SDimitry Andric if (OtherCritIdx) {
22510b57cec5SDimitry Andric LLVM_DEBUG(
22520b57cec5SDimitry Andric dbgs() << " " << Available.getName() << " + Remain CritRes: "
22530b57cec5SDimitry Andric << OtherCritCount / SchedModel->getResourceFactor(OtherCritIdx)
22540b57cec5SDimitry Andric << " " << SchedModel->getResourceName(OtherCritIdx) << "\n");
22550b57cec5SDimitry Andric }
22560b57cec5SDimitry Andric return OtherCritCount;
22570b57cec5SDimitry Andric }
22580b57cec5SDimitry Andric
releaseNode(SUnit * SU,unsigned ReadyCycle,bool InPQueue,unsigned Idx)2259480093f4SDimitry Andric void SchedBoundary::releaseNode(SUnit *SU, unsigned ReadyCycle, bool InPQueue,
2260480093f4SDimitry Andric unsigned Idx) {
22610b57cec5SDimitry Andric assert(SU->getInstr() && "Scheduled SUnit must have instr");
22620b57cec5SDimitry Andric
22630b57cec5SDimitry Andric #ifndef NDEBUG
22640b57cec5SDimitry Andric // ReadyCycle was been bumped up to the CurrCycle when this node was
22650b57cec5SDimitry Andric // scheduled, but CurrCycle may have been eagerly advanced immediately after
22660b57cec5SDimitry Andric // scheduling, so may now be greater than ReadyCycle.
22670b57cec5SDimitry Andric if (ReadyCycle > CurrCycle)
22680b57cec5SDimitry Andric MaxObservedStall = std::max(ReadyCycle - CurrCycle, MaxObservedStall);
22690b57cec5SDimitry Andric #endif
22700b57cec5SDimitry Andric
22710b57cec5SDimitry Andric if (ReadyCycle < MinReadyCycle)
22720b57cec5SDimitry Andric MinReadyCycle = ReadyCycle;
22730b57cec5SDimitry Andric
22740b57cec5SDimitry Andric // Check for interlocks first. For the purpose of other heuristics, an
22750b57cec5SDimitry Andric // instruction that cannot issue appears as if it's not in the ReadyQueue.
22760b57cec5SDimitry Andric bool IsBuffered = SchedModel->getMicroOpBufferSize() != 0;
2277480093f4SDimitry Andric bool HazardDetected = (!IsBuffered && ReadyCycle > CurrCycle) ||
2278480093f4SDimitry Andric checkHazard(SU) || (Available.size() >= ReadyListLimit);
2279480093f4SDimitry Andric
2280480093f4SDimitry Andric if (!HazardDetected) {
22810b57cec5SDimitry Andric Available.push(SU);
2282480093f4SDimitry Andric
2283480093f4SDimitry Andric if (InPQueue)
2284480093f4SDimitry Andric Pending.remove(Pending.begin() + Idx);
2285480093f4SDimitry Andric return;
2286480093f4SDimitry Andric }
2287480093f4SDimitry Andric
2288480093f4SDimitry Andric if (!InPQueue)
2289480093f4SDimitry Andric Pending.push(SU);
22900b57cec5SDimitry Andric }
22910b57cec5SDimitry Andric
22920b57cec5SDimitry Andric /// Move the boundary of scheduled code by one cycle.
bumpCycle(unsigned NextCycle)22930b57cec5SDimitry Andric void SchedBoundary::bumpCycle(unsigned NextCycle) {
22940b57cec5SDimitry Andric if (SchedModel->getMicroOpBufferSize() == 0) {
22950b57cec5SDimitry Andric assert(MinReadyCycle < std::numeric_limits<unsigned>::max() &&
22960b57cec5SDimitry Andric "MinReadyCycle uninitialized");
22970b57cec5SDimitry Andric if (MinReadyCycle > NextCycle)
22980b57cec5SDimitry Andric NextCycle = MinReadyCycle;
22990b57cec5SDimitry Andric }
23000b57cec5SDimitry Andric // Update the current micro-ops, which will issue in the next cycle.
23010b57cec5SDimitry Andric unsigned DecMOps = SchedModel->getIssueWidth() * (NextCycle - CurrCycle);
23020b57cec5SDimitry Andric CurrMOps = (CurrMOps <= DecMOps) ? 0 : CurrMOps - DecMOps;
23030b57cec5SDimitry Andric
23040b57cec5SDimitry Andric // Decrement DependentLatency based on the next cycle.
23050b57cec5SDimitry Andric if ((NextCycle - CurrCycle) > DependentLatency)
23060b57cec5SDimitry Andric DependentLatency = 0;
23070b57cec5SDimitry Andric else
23080b57cec5SDimitry Andric DependentLatency -= (NextCycle - CurrCycle);
23090b57cec5SDimitry Andric
23100b57cec5SDimitry Andric if (!HazardRec->isEnabled()) {
23110b57cec5SDimitry Andric // Bypass HazardRec virtual calls.
23120b57cec5SDimitry Andric CurrCycle = NextCycle;
23130b57cec5SDimitry Andric } else {
23140b57cec5SDimitry Andric // Bypass getHazardType calls in case of long latency.
23150b57cec5SDimitry Andric for (; CurrCycle != NextCycle; ++CurrCycle) {
23160b57cec5SDimitry Andric if (isTop())
23170b57cec5SDimitry Andric HazardRec->AdvanceCycle();
23180b57cec5SDimitry Andric else
23190b57cec5SDimitry Andric HazardRec->RecedeCycle();
23200b57cec5SDimitry Andric }
23210b57cec5SDimitry Andric }
23220b57cec5SDimitry Andric CheckPending = true;
23230b57cec5SDimitry Andric IsResourceLimited =
23240b57cec5SDimitry Andric checkResourceLimit(SchedModel->getLatencyFactor(), getCriticalCount(),
23250b57cec5SDimitry Andric getScheduledLatency(), true);
23260b57cec5SDimitry Andric
23270b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Cycle: " << CurrCycle << ' ' << Available.getName()
23280b57cec5SDimitry Andric << '\n');
23290b57cec5SDimitry Andric }
23300b57cec5SDimitry Andric
incExecutedResources(unsigned PIdx,unsigned Count)23310b57cec5SDimitry Andric void SchedBoundary::incExecutedResources(unsigned PIdx, unsigned Count) {
23320b57cec5SDimitry Andric ExecutedResCounts[PIdx] += Count;
23330b57cec5SDimitry Andric if (ExecutedResCounts[PIdx] > MaxExecutedResCount)
23340b57cec5SDimitry Andric MaxExecutedResCount = ExecutedResCounts[PIdx];
23350b57cec5SDimitry Andric }
23360b57cec5SDimitry Andric
23370b57cec5SDimitry Andric /// Add the given processor resource to this scheduled zone.
23380b57cec5SDimitry Andric ///
23390b57cec5SDimitry Andric /// \param Cycles indicates the number of consecutive (non-pipelined) cycles
23400b57cec5SDimitry Andric /// during which this resource is consumed.
23410b57cec5SDimitry Andric ///
23420b57cec5SDimitry Andric /// \return the next cycle at which the instruction may execute without
23430b57cec5SDimitry Andric /// oversubscribing resources.
countResource(const MCSchedClassDesc * SC,unsigned PIdx,unsigned Cycles,unsigned NextCycle)2344*5f7ddb14SDimitry Andric unsigned SchedBoundary::countResource(const MCSchedClassDesc *SC, unsigned PIdx,
2345*5f7ddb14SDimitry Andric unsigned Cycles, unsigned NextCycle) {
23460b57cec5SDimitry Andric unsigned Factor = SchedModel->getResourceFactor(PIdx);
23470b57cec5SDimitry Andric unsigned Count = Factor * Cycles;
23480b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " " << SchedModel->getResourceName(PIdx) << " +"
23490b57cec5SDimitry Andric << Cycles << "x" << Factor << "u\n");
23500b57cec5SDimitry Andric
23510b57cec5SDimitry Andric // Update Executed resources counts.
23520b57cec5SDimitry Andric incExecutedResources(PIdx, Count);
23530b57cec5SDimitry Andric assert(Rem->RemainingCounts[PIdx] >= Count && "resource double counted");
23540b57cec5SDimitry Andric Rem->RemainingCounts[PIdx] -= Count;
23550b57cec5SDimitry Andric
23560b57cec5SDimitry Andric // Check if this resource exceeds the current critical resource. If so, it
23570b57cec5SDimitry Andric // becomes the critical resource.
23580b57cec5SDimitry Andric if (ZoneCritResIdx != PIdx && (getResourceCount(PIdx) > getCriticalCount())) {
23590b57cec5SDimitry Andric ZoneCritResIdx = PIdx;
23600b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " *** Critical resource "
23610b57cec5SDimitry Andric << SchedModel->getResourceName(PIdx) << ": "
23620b57cec5SDimitry Andric << getResourceCount(PIdx) / SchedModel->getLatencyFactor()
23630b57cec5SDimitry Andric << "c\n");
23640b57cec5SDimitry Andric }
23650b57cec5SDimitry Andric // For reserved resources, record the highest cycle using the resource.
23660b57cec5SDimitry Andric unsigned NextAvailable, InstanceIdx;
2367*5f7ddb14SDimitry Andric std::tie(NextAvailable, InstanceIdx) = getNextResourceCycle(SC, PIdx, Cycles);
23680b57cec5SDimitry Andric if (NextAvailable > CurrCycle) {
23690b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " Resource conflict: "
23700b57cec5SDimitry Andric << SchedModel->getResourceName(PIdx)
23710b57cec5SDimitry Andric << '[' << InstanceIdx - ReservedCyclesIndex[PIdx] << ']'
23720b57cec5SDimitry Andric << " reserved until @" << NextAvailable << "\n");
23730b57cec5SDimitry Andric }
23740b57cec5SDimitry Andric return NextAvailable;
23750b57cec5SDimitry Andric }
23760b57cec5SDimitry Andric
23770b57cec5SDimitry Andric /// Move the boundary of scheduled code by one SUnit.
bumpNode(SUnit * SU)23780b57cec5SDimitry Andric void SchedBoundary::bumpNode(SUnit *SU) {
23790b57cec5SDimitry Andric // Update the reservation table.
23800b57cec5SDimitry Andric if (HazardRec->isEnabled()) {
23810b57cec5SDimitry Andric if (!isTop() && SU->isCall) {
23820b57cec5SDimitry Andric // Calls are scheduled with their preceding instructions. For bottom-up
23830b57cec5SDimitry Andric // scheduling, clear the pipeline state before emitting.
23840b57cec5SDimitry Andric HazardRec->Reset();
23850b57cec5SDimitry Andric }
23860b57cec5SDimitry Andric HazardRec->EmitInstruction(SU);
23870b57cec5SDimitry Andric // Scheduling an instruction may have made pending instructions available.
23880b57cec5SDimitry Andric CheckPending = true;
23890b57cec5SDimitry Andric }
23900b57cec5SDimitry Andric // checkHazard should prevent scheduling multiple instructions per cycle that
23910b57cec5SDimitry Andric // exceed the issue width.
23920b57cec5SDimitry Andric const MCSchedClassDesc *SC = DAG->getSchedClass(SU);
23930b57cec5SDimitry Andric unsigned IncMOps = SchedModel->getNumMicroOps(SU->getInstr());
23940b57cec5SDimitry Andric assert(
23950b57cec5SDimitry Andric (CurrMOps == 0 || (CurrMOps + IncMOps) <= SchedModel->getIssueWidth()) &&
23960b57cec5SDimitry Andric "Cannot schedule this instruction's MicroOps in the current cycle.");
23970b57cec5SDimitry Andric
23980b57cec5SDimitry Andric unsigned ReadyCycle = (isTop() ? SU->TopReadyCycle : SU->BotReadyCycle);
23990b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " Ready @" << ReadyCycle << "c\n");
24000b57cec5SDimitry Andric
24010b57cec5SDimitry Andric unsigned NextCycle = CurrCycle;
24020b57cec5SDimitry Andric switch (SchedModel->getMicroOpBufferSize()) {
24030b57cec5SDimitry Andric case 0:
24040b57cec5SDimitry Andric assert(ReadyCycle <= CurrCycle && "Broken PendingQueue");
24050b57cec5SDimitry Andric break;
24060b57cec5SDimitry Andric case 1:
24070b57cec5SDimitry Andric if (ReadyCycle > NextCycle) {
24080b57cec5SDimitry Andric NextCycle = ReadyCycle;
24090b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " *** Stall until: " << ReadyCycle << "\n");
24100b57cec5SDimitry Andric }
24110b57cec5SDimitry Andric break;
24120b57cec5SDimitry Andric default:
24130b57cec5SDimitry Andric // We don't currently model the OOO reorder buffer, so consider all
24140b57cec5SDimitry Andric // scheduled MOps to be "retired". We do loosely model in-order resource
24150b57cec5SDimitry Andric // latency. If this instruction uses an in-order resource, account for any
24160b57cec5SDimitry Andric // likely stall cycles.
24170b57cec5SDimitry Andric if (SU->isUnbuffered && ReadyCycle > NextCycle)
24180b57cec5SDimitry Andric NextCycle = ReadyCycle;
24190b57cec5SDimitry Andric break;
24200b57cec5SDimitry Andric }
24210b57cec5SDimitry Andric RetiredMOps += IncMOps;
24220b57cec5SDimitry Andric
24230b57cec5SDimitry Andric // Update resource counts and critical resource.
24240b57cec5SDimitry Andric if (SchedModel->hasInstrSchedModel()) {
24250b57cec5SDimitry Andric unsigned DecRemIssue = IncMOps * SchedModel->getMicroOpFactor();
24260b57cec5SDimitry Andric assert(Rem->RemIssueCount >= DecRemIssue && "MOps double counted");
24270b57cec5SDimitry Andric Rem->RemIssueCount -= DecRemIssue;
24280b57cec5SDimitry Andric if (ZoneCritResIdx) {
24290b57cec5SDimitry Andric // Scale scheduled micro-ops for comparing with the critical resource.
24300b57cec5SDimitry Andric unsigned ScaledMOps =
24310b57cec5SDimitry Andric RetiredMOps * SchedModel->getMicroOpFactor();
24320b57cec5SDimitry Andric
24330b57cec5SDimitry Andric // If scaled micro-ops are now more than the previous critical resource by
24340b57cec5SDimitry Andric // a full cycle, then micro-ops issue becomes critical.
24350b57cec5SDimitry Andric if ((int)(ScaledMOps - getResourceCount(ZoneCritResIdx))
24360b57cec5SDimitry Andric >= (int)SchedModel->getLatencyFactor()) {
24370b57cec5SDimitry Andric ZoneCritResIdx = 0;
24380b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " *** Critical resource NumMicroOps: "
24390b57cec5SDimitry Andric << ScaledMOps / SchedModel->getLatencyFactor()
24400b57cec5SDimitry Andric << "c\n");
24410b57cec5SDimitry Andric }
24420b57cec5SDimitry Andric }
24430b57cec5SDimitry Andric for (TargetSchedModel::ProcResIter
24440b57cec5SDimitry Andric PI = SchedModel->getWriteProcResBegin(SC),
24450b57cec5SDimitry Andric PE = SchedModel->getWriteProcResEnd(SC); PI != PE; ++PI) {
24460b57cec5SDimitry Andric unsigned RCycle =
2447*5f7ddb14SDimitry Andric countResource(SC, PI->ProcResourceIdx, PI->Cycles, NextCycle);
24480b57cec5SDimitry Andric if (RCycle > NextCycle)
24490b57cec5SDimitry Andric NextCycle = RCycle;
24500b57cec5SDimitry Andric }
24510b57cec5SDimitry Andric if (SU->hasReservedResource) {
24520b57cec5SDimitry Andric // For reserved resources, record the highest cycle using the resource.
24530b57cec5SDimitry Andric // For top-down scheduling, this is the cycle in which we schedule this
24540b57cec5SDimitry Andric // instruction plus the number of cycles the operations reserves the
24550b57cec5SDimitry Andric // resource. For bottom-up is it simply the instruction's cycle.
24560b57cec5SDimitry Andric for (TargetSchedModel::ProcResIter
24570b57cec5SDimitry Andric PI = SchedModel->getWriteProcResBegin(SC),
24580b57cec5SDimitry Andric PE = SchedModel->getWriteProcResEnd(SC); PI != PE; ++PI) {
24590b57cec5SDimitry Andric unsigned PIdx = PI->ProcResourceIdx;
24600b57cec5SDimitry Andric if (SchedModel->getProcResource(PIdx)->BufferSize == 0) {
24610b57cec5SDimitry Andric unsigned ReservedUntil, InstanceIdx;
2462*5f7ddb14SDimitry Andric std::tie(ReservedUntil, InstanceIdx) =
2463*5f7ddb14SDimitry Andric getNextResourceCycle(SC, PIdx, 0);
24640b57cec5SDimitry Andric if (isTop()) {
24650b57cec5SDimitry Andric ReservedCycles[InstanceIdx] =
24660b57cec5SDimitry Andric std::max(ReservedUntil, NextCycle + PI->Cycles);
24670b57cec5SDimitry Andric } else
24680b57cec5SDimitry Andric ReservedCycles[InstanceIdx] = NextCycle;
24690b57cec5SDimitry Andric }
24700b57cec5SDimitry Andric }
24710b57cec5SDimitry Andric }
24720b57cec5SDimitry Andric }
24730b57cec5SDimitry Andric // Update ExpectedLatency and DependentLatency.
24740b57cec5SDimitry Andric unsigned &TopLatency = isTop() ? ExpectedLatency : DependentLatency;
24750b57cec5SDimitry Andric unsigned &BotLatency = isTop() ? DependentLatency : ExpectedLatency;
24760b57cec5SDimitry Andric if (SU->getDepth() > TopLatency) {
24770b57cec5SDimitry Andric TopLatency = SU->getDepth();
24780b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " " << Available.getName() << " TopLatency SU("
24790b57cec5SDimitry Andric << SU->NodeNum << ") " << TopLatency << "c\n");
24800b57cec5SDimitry Andric }
24810b57cec5SDimitry Andric if (SU->getHeight() > BotLatency) {
24820b57cec5SDimitry Andric BotLatency = SU->getHeight();
24830b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " " << Available.getName() << " BotLatency SU("
24840b57cec5SDimitry Andric << SU->NodeNum << ") " << BotLatency << "c\n");
24850b57cec5SDimitry Andric }
24860b57cec5SDimitry Andric // If we stall for any reason, bump the cycle.
24870b57cec5SDimitry Andric if (NextCycle > CurrCycle)
24880b57cec5SDimitry Andric bumpCycle(NextCycle);
24890b57cec5SDimitry Andric else
24900b57cec5SDimitry Andric // After updating ZoneCritResIdx and ExpectedLatency, check if we're
24910b57cec5SDimitry Andric // resource limited. If a stall occurred, bumpCycle does this.
24920b57cec5SDimitry Andric IsResourceLimited =
24930b57cec5SDimitry Andric checkResourceLimit(SchedModel->getLatencyFactor(), getCriticalCount(),
24940b57cec5SDimitry Andric getScheduledLatency(), true);
24950b57cec5SDimitry Andric
24960b57cec5SDimitry Andric // Update CurrMOps after calling bumpCycle to handle stalls, since bumpCycle
24970b57cec5SDimitry Andric // resets CurrMOps. Loop to handle instructions with more MOps than issue in
24980b57cec5SDimitry Andric // one cycle. Since we commonly reach the max MOps here, opportunistically
24990b57cec5SDimitry Andric // bump the cycle to avoid uselessly checking everything in the readyQ.
25000b57cec5SDimitry Andric CurrMOps += IncMOps;
25010b57cec5SDimitry Andric
25020b57cec5SDimitry Andric // Bump the cycle count for issue group constraints.
25030b57cec5SDimitry Andric // This must be done after NextCycle has been adjust for all other stalls.
25040b57cec5SDimitry Andric // Calling bumpCycle(X) will reduce CurrMOps by one issue group and set
25050b57cec5SDimitry Andric // currCycle to X.
25060b57cec5SDimitry Andric if ((isTop() && SchedModel->mustEndGroup(SU->getInstr())) ||
25070b57cec5SDimitry Andric (!isTop() && SchedModel->mustBeginGroup(SU->getInstr()))) {
25080b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " Bump cycle to " << (isTop() ? "end" : "begin")
25090b57cec5SDimitry Andric << " group\n");
25100b57cec5SDimitry Andric bumpCycle(++NextCycle);
25110b57cec5SDimitry Andric }
25120b57cec5SDimitry Andric
25130b57cec5SDimitry Andric while (CurrMOps >= SchedModel->getIssueWidth()) {
25140b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " *** Max MOps " << CurrMOps << " at cycle "
25150b57cec5SDimitry Andric << CurrCycle << '\n');
25160b57cec5SDimitry Andric bumpCycle(++NextCycle);
25170b57cec5SDimitry Andric }
25180b57cec5SDimitry Andric LLVM_DEBUG(dumpScheduledState());
25190b57cec5SDimitry Andric }
25200b57cec5SDimitry Andric
25210b57cec5SDimitry Andric /// Release pending ready nodes in to the available queue. This makes them
25220b57cec5SDimitry Andric /// visible to heuristics.
releasePending()25230b57cec5SDimitry Andric void SchedBoundary::releasePending() {
25240b57cec5SDimitry Andric // If the available queue is empty, it is safe to reset MinReadyCycle.
25250b57cec5SDimitry Andric if (Available.empty())
25260b57cec5SDimitry Andric MinReadyCycle = std::numeric_limits<unsigned>::max();
25270b57cec5SDimitry Andric
25280b57cec5SDimitry Andric // Check to see if any of the pending instructions are ready to issue. If
25290b57cec5SDimitry Andric // so, add them to the available queue.
2530480093f4SDimitry Andric for (unsigned I = 0, E = Pending.size(); I < E; ++I) {
2531480093f4SDimitry Andric SUnit *SU = *(Pending.begin() + I);
25320b57cec5SDimitry Andric unsigned ReadyCycle = isTop() ? SU->TopReadyCycle : SU->BotReadyCycle;
25330b57cec5SDimitry Andric
25340b57cec5SDimitry Andric if (ReadyCycle < MinReadyCycle)
25350b57cec5SDimitry Andric MinReadyCycle = ReadyCycle;
25360b57cec5SDimitry Andric
25370b57cec5SDimitry Andric if (Available.size() >= ReadyListLimit)
25380b57cec5SDimitry Andric break;
25390b57cec5SDimitry Andric
2540480093f4SDimitry Andric releaseNode(SU, ReadyCycle, true, I);
2541480093f4SDimitry Andric if (E != Pending.size()) {
2542480093f4SDimitry Andric --I;
2543480093f4SDimitry Andric --E;
2544480093f4SDimitry Andric }
25450b57cec5SDimitry Andric }
25460b57cec5SDimitry Andric CheckPending = false;
25470b57cec5SDimitry Andric }
25480b57cec5SDimitry Andric
25490b57cec5SDimitry Andric /// Remove SU from the ready set for this boundary.
removeReady(SUnit * SU)25500b57cec5SDimitry Andric void SchedBoundary::removeReady(SUnit *SU) {
25510b57cec5SDimitry Andric if (Available.isInQueue(SU))
25520b57cec5SDimitry Andric Available.remove(Available.find(SU));
25530b57cec5SDimitry Andric else {
25540b57cec5SDimitry Andric assert(Pending.isInQueue(SU) && "bad ready count");
25550b57cec5SDimitry Andric Pending.remove(Pending.find(SU));
25560b57cec5SDimitry Andric }
25570b57cec5SDimitry Andric }
25580b57cec5SDimitry Andric
25590b57cec5SDimitry Andric /// If this queue only has one ready candidate, return it. As a side effect,
25600b57cec5SDimitry Andric /// defer any nodes that now hit a hazard, and advance the cycle until at least
25610b57cec5SDimitry Andric /// one node is ready. If multiple instructions are ready, return NULL.
pickOnlyChoice()25620b57cec5SDimitry Andric SUnit *SchedBoundary::pickOnlyChoice() {
25630b57cec5SDimitry Andric if (CheckPending)
25640b57cec5SDimitry Andric releasePending();
25650b57cec5SDimitry Andric
25660b57cec5SDimitry Andric // Defer any ready instrs that now have a hazard.
25670b57cec5SDimitry Andric for (ReadyQueue::iterator I = Available.begin(); I != Available.end();) {
25680b57cec5SDimitry Andric if (checkHazard(*I)) {
25690b57cec5SDimitry Andric Pending.push(*I);
25700b57cec5SDimitry Andric I = Available.remove(I);
25710b57cec5SDimitry Andric continue;
25720b57cec5SDimitry Andric }
25730b57cec5SDimitry Andric ++I;
25740b57cec5SDimitry Andric }
25750b57cec5SDimitry Andric for (unsigned i = 0; Available.empty(); ++i) {
25760b57cec5SDimitry Andric // FIXME: Re-enable assert once PR20057 is resolved.
25770b57cec5SDimitry Andric // assert(i <= (HazardRec->getMaxLookAhead() + MaxObservedStall) &&
25780b57cec5SDimitry Andric // "permanent hazard");
25790b57cec5SDimitry Andric (void)i;
25800b57cec5SDimitry Andric bumpCycle(CurrCycle + 1);
25810b57cec5SDimitry Andric releasePending();
25820b57cec5SDimitry Andric }
25830b57cec5SDimitry Andric
25840b57cec5SDimitry Andric LLVM_DEBUG(Pending.dump());
25850b57cec5SDimitry Andric LLVM_DEBUG(Available.dump());
25860b57cec5SDimitry Andric
25870b57cec5SDimitry Andric if (Available.size() == 1)
25880b57cec5SDimitry Andric return *Available.begin();
25890b57cec5SDimitry Andric return nullptr;
25900b57cec5SDimitry Andric }
25910b57cec5SDimitry Andric
25920b57cec5SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
25930b57cec5SDimitry Andric // This is useful information to dump after bumpNode.
25940b57cec5SDimitry Andric // Note that the Queue contents are more useful before pickNodeFromQueue.
dumpScheduledState() const25950b57cec5SDimitry Andric LLVM_DUMP_METHOD void SchedBoundary::dumpScheduledState() const {
25960b57cec5SDimitry Andric unsigned ResFactor;
25970b57cec5SDimitry Andric unsigned ResCount;
25980b57cec5SDimitry Andric if (ZoneCritResIdx) {
25990b57cec5SDimitry Andric ResFactor = SchedModel->getResourceFactor(ZoneCritResIdx);
26000b57cec5SDimitry Andric ResCount = getResourceCount(ZoneCritResIdx);
26010b57cec5SDimitry Andric } else {
26020b57cec5SDimitry Andric ResFactor = SchedModel->getMicroOpFactor();
26030b57cec5SDimitry Andric ResCount = RetiredMOps * ResFactor;
26040b57cec5SDimitry Andric }
26050b57cec5SDimitry Andric unsigned LFactor = SchedModel->getLatencyFactor();
26060b57cec5SDimitry Andric dbgs() << Available.getName() << " @" << CurrCycle << "c\n"
26070b57cec5SDimitry Andric << " Retired: " << RetiredMOps;
26080b57cec5SDimitry Andric dbgs() << "\n Executed: " << getExecutedCount() / LFactor << "c";
26090b57cec5SDimitry Andric dbgs() << "\n Critical: " << ResCount / LFactor << "c, "
26100b57cec5SDimitry Andric << ResCount / ResFactor << " "
26110b57cec5SDimitry Andric << SchedModel->getResourceName(ZoneCritResIdx)
26120b57cec5SDimitry Andric << "\n ExpectedLatency: " << ExpectedLatency << "c\n"
26130b57cec5SDimitry Andric << (IsResourceLimited ? " - Resource" : " - Latency")
26140b57cec5SDimitry Andric << " limited.\n";
26150b57cec5SDimitry Andric }
26160b57cec5SDimitry Andric #endif
26170b57cec5SDimitry Andric
26180b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
26190b57cec5SDimitry Andric // GenericScheduler - Generic implementation of MachineSchedStrategy.
26200b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
26210b57cec5SDimitry Andric
26220b57cec5SDimitry Andric void GenericSchedulerBase::SchedCandidate::
initResourceDelta(const ScheduleDAGMI * DAG,const TargetSchedModel * SchedModel)26230b57cec5SDimitry Andric initResourceDelta(const ScheduleDAGMI *DAG,
26240b57cec5SDimitry Andric const TargetSchedModel *SchedModel) {
26250b57cec5SDimitry Andric if (!Policy.ReduceResIdx && !Policy.DemandResIdx)
26260b57cec5SDimitry Andric return;
26270b57cec5SDimitry Andric
26280b57cec5SDimitry Andric const MCSchedClassDesc *SC = DAG->getSchedClass(SU);
26290b57cec5SDimitry Andric for (TargetSchedModel::ProcResIter
26300b57cec5SDimitry Andric PI = SchedModel->getWriteProcResBegin(SC),
26310b57cec5SDimitry Andric PE = SchedModel->getWriteProcResEnd(SC); PI != PE; ++PI) {
26320b57cec5SDimitry Andric if (PI->ProcResourceIdx == Policy.ReduceResIdx)
26330b57cec5SDimitry Andric ResDelta.CritResources += PI->Cycles;
26340b57cec5SDimitry Andric if (PI->ProcResourceIdx == Policy.DemandResIdx)
26350b57cec5SDimitry Andric ResDelta.DemandedResources += PI->Cycles;
26360b57cec5SDimitry Andric }
26370b57cec5SDimitry Andric }
26380b57cec5SDimitry Andric
26390b57cec5SDimitry Andric /// Compute remaining latency. We need this both to determine whether the
26400b57cec5SDimitry Andric /// overall schedule has become latency-limited and whether the instructions
26410b57cec5SDimitry Andric /// outside this zone are resource or latency limited.
26420b57cec5SDimitry Andric ///
26430b57cec5SDimitry Andric /// The "dependent" latency is updated incrementally during scheduling as the
26440b57cec5SDimitry Andric /// max height/depth of scheduled nodes minus the cycles since it was
26450b57cec5SDimitry Andric /// scheduled:
26460b57cec5SDimitry Andric /// DLat = max (N.depth - (CurrCycle - N.ReadyCycle) for N in Zone
26470b57cec5SDimitry Andric ///
26480b57cec5SDimitry Andric /// The "independent" latency is the max ready queue depth:
26490b57cec5SDimitry Andric /// ILat = max N.depth for N in Available|Pending
26500b57cec5SDimitry Andric ///
26510b57cec5SDimitry Andric /// RemainingLatency is the greater of independent and dependent latency.
26520b57cec5SDimitry Andric ///
26530b57cec5SDimitry Andric /// These computations are expensive, especially in DAGs with many edges, so
26540b57cec5SDimitry Andric /// only do them if necessary.
computeRemLatency(SchedBoundary & CurrZone)26550b57cec5SDimitry Andric static unsigned computeRemLatency(SchedBoundary &CurrZone) {
26560b57cec5SDimitry Andric unsigned RemLatency = CurrZone.getDependentLatency();
26570b57cec5SDimitry Andric RemLatency = std::max(RemLatency,
26580b57cec5SDimitry Andric CurrZone.findMaxLatency(CurrZone.Available.elements()));
26590b57cec5SDimitry Andric RemLatency = std::max(RemLatency,
26600b57cec5SDimitry Andric CurrZone.findMaxLatency(CurrZone.Pending.elements()));
26610b57cec5SDimitry Andric return RemLatency;
26620b57cec5SDimitry Andric }
26630b57cec5SDimitry Andric
26640b57cec5SDimitry Andric /// Returns true if the current cycle plus remaning latency is greater than
26650b57cec5SDimitry Andric /// the critical path in the scheduling region.
shouldReduceLatency(const CandPolicy & Policy,SchedBoundary & CurrZone,bool ComputeRemLatency,unsigned & RemLatency) const26660b57cec5SDimitry Andric bool GenericSchedulerBase::shouldReduceLatency(const CandPolicy &Policy,
26670b57cec5SDimitry Andric SchedBoundary &CurrZone,
26680b57cec5SDimitry Andric bool ComputeRemLatency,
26690b57cec5SDimitry Andric unsigned &RemLatency) const {
26700b57cec5SDimitry Andric // The current cycle is already greater than the critical path, so we are
26710b57cec5SDimitry Andric // already latency limited and don't need to compute the remaining latency.
26720b57cec5SDimitry Andric if (CurrZone.getCurrCycle() > Rem.CriticalPath)
26730b57cec5SDimitry Andric return true;
26740b57cec5SDimitry Andric
26750b57cec5SDimitry Andric // If we haven't scheduled anything yet, then we aren't latency limited.
26760b57cec5SDimitry Andric if (CurrZone.getCurrCycle() == 0)
26770b57cec5SDimitry Andric return false;
26780b57cec5SDimitry Andric
26790b57cec5SDimitry Andric if (ComputeRemLatency)
26800b57cec5SDimitry Andric RemLatency = computeRemLatency(CurrZone);
26810b57cec5SDimitry Andric
26820b57cec5SDimitry Andric return RemLatency + CurrZone.getCurrCycle() > Rem.CriticalPath;
26830b57cec5SDimitry Andric }
26840b57cec5SDimitry Andric
26850b57cec5SDimitry Andric /// Set the CandPolicy given a scheduling zone given the current resources and
26860b57cec5SDimitry Andric /// latencies inside and outside the zone.
setPolicy(CandPolicy & Policy,bool IsPostRA,SchedBoundary & CurrZone,SchedBoundary * OtherZone)26870b57cec5SDimitry Andric void GenericSchedulerBase::setPolicy(CandPolicy &Policy, bool IsPostRA,
26880b57cec5SDimitry Andric SchedBoundary &CurrZone,
26890b57cec5SDimitry Andric SchedBoundary *OtherZone) {
26900b57cec5SDimitry Andric // Apply preemptive heuristics based on the total latency and resources
26910b57cec5SDimitry Andric // inside and outside this zone. Potential stalls should be considered before
26920b57cec5SDimitry Andric // following this policy.
26930b57cec5SDimitry Andric
26940b57cec5SDimitry Andric // Compute the critical resource outside the zone.
26950b57cec5SDimitry Andric unsigned OtherCritIdx = 0;
26960b57cec5SDimitry Andric unsigned OtherCount =
26970b57cec5SDimitry Andric OtherZone ? OtherZone->getOtherResourceCount(OtherCritIdx) : 0;
26980b57cec5SDimitry Andric
26990b57cec5SDimitry Andric bool OtherResLimited = false;
27000b57cec5SDimitry Andric unsigned RemLatency = 0;
27010b57cec5SDimitry Andric bool RemLatencyComputed = false;
27020b57cec5SDimitry Andric if (SchedModel->hasInstrSchedModel() && OtherCount != 0) {
27030b57cec5SDimitry Andric RemLatency = computeRemLatency(CurrZone);
27040b57cec5SDimitry Andric RemLatencyComputed = true;
27050b57cec5SDimitry Andric OtherResLimited = checkResourceLimit(SchedModel->getLatencyFactor(),
27060b57cec5SDimitry Andric OtherCount, RemLatency, false);
27070b57cec5SDimitry Andric }
27080b57cec5SDimitry Andric
27090b57cec5SDimitry Andric // Schedule aggressively for latency in PostRA mode. We don't check for
27100b57cec5SDimitry Andric // acyclic latency during PostRA, and highly out-of-order processors will
27110b57cec5SDimitry Andric // skip PostRA scheduling.
27120b57cec5SDimitry Andric if (!OtherResLimited &&
27130b57cec5SDimitry Andric (IsPostRA || shouldReduceLatency(Policy, CurrZone, !RemLatencyComputed,
27140b57cec5SDimitry Andric RemLatency))) {
27150b57cec5SDimitry Andric Policy.ReduceLatency |= true;
27160b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " " << CurrZone.Available.getName()
27170b57cec5SDimitry Andric << " RemainingLatency " << RemLatency << " + "
27180b57cec5SDimitry Andric << CurrZone.getCurrCycle() << "c > CritPath "
27190b57cec5SDimitry Andric << Rem.CriticalPath << "\n");
27200b57cec5SDimitry Andric }
27210b57cec5SDimitry Andric // If the same resource is limiting inside and outside the zone, do nothing.
27220b57cec5SDimitry Andric if (CurrZone.getZoneCritResIdx() == OtherCritIdx)
27230b57cec5SDimitry Andric return;
27240b57cec5SDimitry Andric
27250b57cec5SDimitry Andric LLVM_DEBUG(if (CurrZone.isResourceLimited()) {
27260b57cec5SDimitry Andric dbgs() << " " << CurrZone.Available.getName() << " ResourceLimited: "
27270b57cec5SDimitry Andric << SchedModel->getResourceName(CurrZone.getZoneCritResIdx()) << "\n";
27280b57cec5SDimitry Andric } if (OtherResLimited) dbgs()
27290b57cec5SDimitry Andric << " RemainingLimit: "
27300b57cec5SDimitry Andric << SchedModel->getResourceName(OtherCritIdx) << "\n";
27310b57cec5SDimitry Andric if (!CurrZone.isResourceLimited() && !OtherResLimited) dbgs()
27320b57cec5SDimitry Andric << " Latency limited both directions.\n");
27330b57cec5SDimitry Andric
27340b57cec5SDimitry Andric if (CurrZone.isResourceLimited() && !Policy.ReduceResIdx)
27350b57cec5SDimitry Andric Policy.ReduceResIdx = CurrZone.getZoneCritResIdx();
27360b57cec5SDimitry Andric
27370b57cec5SDimitry Andric if (OtherResLimited)
27380b57cec5SDimitry Andric Policy.DemandResIdx = OtherCritIdx;
27390b57cec5SDimitry Andric }
27400b57cec5SDimitry Andric
27410b57cec5SDimitry Andric #ifndef NDEBUG
getReasonStr(GenericSchedulerBase::CandReason Reason)27420b57cec5SDimitry Andric const char *GenericSchedulerBase::getReasonStr(
27430b57cec5SDimitry Andric GenericSchedulerBase::CandReason Reason) {
27440b57cec5SDimitry Andric switch (Reason) {
27450b57cec5SDimitry Andric case NoCand: return "NOCAND ";
27460b57cec5SDimitry Andric case Only1: return "ONLY1 ";
27470b57cec5SDimitry Andric case PhysReg: return "PHYS-REG ";
27480b57cec5SDimitry Andric case RegExcess: return "REG-EXCESS";
27490b57cec5SDimitry Andric case RegCritical: return "REG-CRIT ";
27500b57cec5SDimitry Andric case Stall: return "STALL ";
27510b57cec5SDimitry Andric case Cluster: return "CLUSTER ";
27520b57cec5SDimitry Andric case Weak: return "WEAK ";
27530b57cec5SDimitry Andric case RegMax: return "REG-MAX ";
27540b57cec5SDimitry Andric case ResourceReduce: return "RES-REDUCE";
27550b57cec5SDimitry Andric case ResourceDemand: return "RES-DEMAND";
27560b57cec5SDimitry Andric case TopDepthReduce: return "TOP-DEPTH ";
27570b57cec5SDimitry Andric case TopPathReduce: return "TOP-PATH ";
27580b57cec5SDimitry Andric case BotHeightReduce:return "BOT-HEIGHT";
27590b57cec5SDimitry Andric case BotPathReduce: return "BOT-PATH ";
27600b57cec5SDimitry Andric case NextDefUse: return "DEF-USE ";
27610b57cec5SDimitry Andric case NodeOrder: return "ORDER ";
27620b57cec5SDimitry Andric };
27630b57cec5SDimitry Andric llvm_unreachable("Unknown reason!");
27640b57cec5SDimitry Andric }
27650b57cec5SDimitry Andric
traceCandidate(const SchedCandidate & Cand)27660b57cec5SDimitry Andric void GenericSchedulerBase::traceCandidate(const SchedCandidate &Cand) {
27670b57cec5SDimitry Andric PressureChange P;
27680b57cec5SDimitry Andric unsigned ResIdx = 0;
27690b57cec5SDimitry Andric unsigned Latency = 0;
27700b57cec5SDimitry Andric switch (Cand.Reason) {
27710b57cec5SDimitry Andric default:
27720b57cec5SDimitry Andric break;
27730b57cec5SDimitry Andric case RegExcess:
27740b57cec5SDimitry Andric P = Cand.RPDelta.Excess;
27750b57cec5SDimitry Andric break;
27760b57cec5SDimitry Andric case RegCritical:
27770b57cec5SDimitry Andric P = Cand.RPDelta.CriticalMax;
27780b57cec5SDimitry Andric break;
27790b57cec5SDimitry Andric case RegMax:
27800b57cec5SDimitry Andric P = Cand.RPDelta.CurrentMax;
27810b57cec5SDimitry Andric break;
27820b57cec5SDimitry Andric case ResourceReduce:
27830b57cec5SDimitry Andric ResIdx = Cand.Policy.ReduceResIdx;
27840b57cec5SDimitry Andric break;
27850b57cec5SDimitry Andric case ResourceDemand:
27860b57cec5SDimitry Andric ResIdx = Cand.Policy.DemandResIdx;
27870b57cec5SDimitry Andric break;
27880b57cec5SDimitry Andric case TopDepthReduce:
27890b57cec5SDimitry Andric Latency = Cand.SU->getDepth();
27900b57cec5SDimitry Andric break;
27910b57cec5SDimitry Andric case TopPathReduce:
27920b57cec5SDimitry Andric Latency = Cand.SU->getHeight();
27930b57cec5SDimitry Andric break;
27940b57cec5SDimitry Andric case BotHeightReduce:
27950b57cec5SDimitry Andric Latency = Cand.SU->getHeight();
27960b57cec5SDimitry Andric break;
27970b57cec5SDimitry Andric case BotPathReduce:
27980b57cec5SDimitry Andric Latency = Cand.SU->getDepth();
27990b57cec5SDimitry Andric break;
28000b57cec5SDimitry Andric }
28010b57cec5SDimitry Andric dbgs() << " Cand SU(" << Cand.SU->NodeNum << ") " << getReasonStr(Cand.Reason);
28020b57cec5SDimitry Andric if (P.isValid())
28030b57cec5SDimitry Andric dbgs() << " " << TRI->getRegPressureSetName(P.getPSet())
28040b57cec5SDimitry Andric << ":" << P.getUnitInc() << " ";
28050b57cec5SDimitry Andric else
28060b57cec5SDimitry Andric dbgs() << " ";
28070b57cec5SDimitry Andric if (ResIdx)
28080b57cec5SDimitry Andric dbgs() << " " << SchedModel->getProcResource(ResIdx)->Name << " ";
28090b57cec5SDimitry Andric else
28100b57cec5SDimitry Andric dbgs() << " ";
28110b57cec5SDimitry Andric if (Latency)
28120b57cec5SDimitry Andric dbgs() << " " << Latency << " cycles ";
28130b57cec5SDimitry Andric else
28140b57cec5SDimitry Andric dbgs() << " ";
28150b57cec5SDimitry Andric dbgs() << '\n';
28160b57cec5SDimitry Andric }
28170b57cec5SDimitry Andric #endif
28180b57cec5SDimitry Andric
28190b57cec5SDimitry Andric namespace llvm {
28200b57cec5SDimitry Andric /// Return true if this heuristic determines order.
2821*5f7ddb14SDimitry Andric /// TODO: Consider refactor return type of these functions as integer or enum,
2822*5f7ddb14SDimitry 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)28230b57cec5SDimitry Andric bool tryLess(int TryVal, int CandVal,
28240b57cec5SDimitry Andric GenericSchedulerBase::SchedCandidate &TryCand,
28250b57cec5SDimitry Andric GenericSchedulerBase::SchedCandidate &Cand,
28260b57cec5SDimitry Andric GenericSchedulerBase::CandReason Reason) {
28270b57cec5SDimitry Andric if (TryVal < CandVal) {
28280b57cec5SDimitry Andric TryCand.Reason = Reason;
28290b57cec5SDimitry Andric return true;
28300b57cec5SDimitry Andric }
28310b57cec5SDimitry Andric if (TryVal > CandVal) {
28320b57cec5SDimitry Andric if (Cand.Reason > Reason)
28330b57cec5SDimitry Andric Cand.Reason = Reason;
28340b57cec5SDimitry Andric return true;
28350b57cec5SDimitry Andric }
28360b57cec5SDimitry Andric return false;
28370b57cec5SDimitry Andric }
28380b57cec5SDimitry Andric
tryGreater(int TryVal,int CandVal,GenericSchedulerBase::SchedCandidate & TryCand,GenericSchedulerBase::SchedCandidate & Cand,GenericSchedulerBase::CandReason Reason)28390b57cec5SDimitry Andric bool tryGreater(int TryVal, int CandVal,
28400b57cec5SDimitry Andric GenericSchedulerBase::SchedCandidate &TryCand,
28410b57cec5SDimitry Andric GenericSchedulerBase::SchedCandidate &Cand,
28420b57cec5SDimitry Andric GenericSchedulerBase::CandReason Reason) {
28430b57cec5SDimitry Andric if (TryVal > CandVal) {
28440b57cec5SDimitry Andric TryCand.Reason = Reason;
28450b57cec5SDimitry Andric return true;
28460b57cec5SDimitry Andric }
28470b57cec5SDimitry Andric if (TryVal < CandVal) {
28480b57cec5SDimitry Andric if (Cand.Reason > Reason)
28490b57cec5SDimitry Andric Cand.Reason = Reason;
28500b57cec5SDimitry Andric return true;
28510b57cec5SDimitry Andric }
28520b57cec5SDimitry Andric return false;
28530b57cec5SDimitry Andric }
28540b57cec5SDimitry Andric
tryLatency(GenericSchedulerBase::SchedCandidate & TryCand,GenericSchedulerBase::SchedCandidate & Cand,SchedBoundary & Zone)28550b57cec5SDimitry Andric bool tryLatency(GenericSchedulerBase::SchedCandidate &TryCand,
28560b57cec5SDimitry Andric GenericSchedulerBase::SchedCandidate &Cand,
28570b57cec5SDimitry Andric SchedBoundary &Zone) {
28580b57cec5SDimitry Andric if (Zone.isTop()) {
2859af732203SDimitry Andric // Prefer the candidate with the lesser depth, but only if one of them has
2860af732203SDimitry Andric // depth greater than the total latency scheduled so far, otherwise either
2861af732203SDimitry Andric // of them could be scheduled now with no stall.
2862af732203SDimitry Andric if (std::max(TryCand.SU->getDepth(), Cand.SU->getDepth()) >
2863af732203SDimitry Andric Zone.getScheduledLatency()) {
28640b57cec5SDimitry Andric if (tryLess(TryCand.SU->getDepth(), Cand.SU->getDepth(),
28650b57cec5SDimitry Andric TryCand, Cand, GenericSchedulerBase::TopDepthReduce))
28660b57cec5SDimitry Andric return true;
28670b57cec5SDimitry Andric }
28680b57cec5SDimitry Andric if (tryGreater(TryCand.SU->getHeight(), Cand.SU->getHeight(),
28690b57cec5SDimitry Andric TryCand, Cand, GenericSchedulerBase::TopPathReduce))
28700b57cec5SDimitry Andric return true;
28710b57cec5SDimitry Andric } else {
2872af732203SDimitry Andric // Prefer the candidate with the lesser height, but only if one of them has
2873af732203SDimitry Andric // height greater than the total latency scheduled so far, otherwise either
2874af732203SDimitry Andric // of them could be scheduled now with no stall.
2875af732203SDimitry Andric if (std::max(TryCand.SU->getHeight(), Cand.SU->getHeight()) >
2876af732203SDimitry Andric Zone.getScheduledLatency()) {
28770b57cec5SDimitry Andric if (tryLess(TryCand.SU->getHeight(), Cand.SU->getHeight(),
28780b57cec5SDimitry Andric TryCand, Cand, GenericSchedulerBase::BotHeightReduce))
28790b57cec5SDimitry Andric return true;
28800b57cec5SDimitry Andric }
28810b57cec5SDimitry Andric if (tryGreater(TryCand.SU->getDepth(), Cand.SU->getDepth(),
28820b57cec5SDimitry Andric TryCand, Cand, GenericSchedulerBase::BotPathReduce))
28830b57cec5SDimitry Andric return true;
28840b57cec5SDimitry Andric }
28850b57cec5SDimitry Andric return false;
28860b57cec5SDimitry Andric }
28870b57cec5SDimitry Andric } // end namespace llvm
28880b57cec5SDimitry Andric
tracePick(GenericSchedulerBase::CandReason Reason,bool IsTop)28890b57cec5SDimitry Andric static void tracePick(GenericSchedulerBase::CandReason Reason, bool IsTop) {
28900b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Pick " << (IsTop ? "Top " : "Bot ")
28910b57cec5SDimitry Andric << GenericSchedulerBase::getReasonStr(Reason) << '\n');
28920b57cec5SDimitry Andric }
28930b57cec5SDimitry Andric
tracePick(const GenericSchedulerBase::SchedCandidate & Cand)28940b57cec5SDimitry Andric static void tracePick(const GenericSchedulerBase::SchedCandidate &Cand) {
28950b57cec5SDimitry Andric tracePick(Cand.Reason, Cand.AtTop);
28960b57cec5SDimitry Andric }
28970b57cec5SDimitry Andric
initialize(ScheduleDAGMI * dag)28980b57cec5SDimitry Andric void GenericScheduler::initialize(ScheduleDAGMI *dag) {
28990b57cec5SDimitry Andric assert(dag->hasVRegLiveness() &&
29000b57cec5SDimitry Andric "(PreRA)GenericScheduler needs vreg liveness");
29010b57cec5SDimitry Andric DAG = static_cast<ScheduleDAGMILive*>(dag);
29020b57cec5SDimitry Andric SchedModel = DAG->getSchedModel();
29030b57cec5SDimitry Andric TRI = DAG->TRI;
29040b57cec5SDimitry Andric
29055ffd83dbSDimitry Andric if (RegionPolicy.ComputeDFSResult)
29065ffd83dbSDimitry Andric DAG->computeDFSResult();
29075ffd83dbSDimitry Andric
29080b57cec5SDimitry Andric Rem.init(DAG, SchedModel);
29090b57cec5SDimitry Andric Top.init(DAG, SchedModel, &Rem);
29100b57cec5SDimitry Andric Bot.init(DAG, SchedModel, &Rem);
29110b57cec5SDimitry Andric
29120b57cec5SDimitry Andric // Initialize resource counts.
29130b57cec5SDimitry Andric
29140b57cec5SDimitry Andric // Initialize the HazardRecognizers. If itineraries don't exist, are empty, or
29150b57cec5SDimitry Andric // are disabled, then these HazardRecs will be disabled.
29160b57cec5SDimitry Andric const InstrItineraryData *Itin = SchedModel->getInstrItineraries();
29170b57cec5SDimitry Andric if (!Top.HazardRec) {
29180b57cec5SDimitry Andric Top.HazardRec =
29190b57cec5SDimitry Andric DAG->MF.getSubtarget().getInstrInfo()->CreateTargetMIHazardRecognizer(
29200b57cec5SDimitry Andric Itin, DAG);
29210b57cec5SDimitry Andric }
29220b57cec5SDimitry Andric if (!Bot.HazardRec) {
29230b57cec5SDimitry Andric Bot.HazardRec =
29240b57cec5SDimitry Andric DAG->MF.getSubtarget().getInstrInfo()->CreateTargetMIHazardRecognizer(
29250b57cec5SDimitry Andric Itin, DAG);
29260b57cec5SDimitry Andric }
29270b57cec5SDimitry Andric TopCand.SU = nullptr;
29280b57cec5SDimitry Andric BotCand.SU = nullptr;
29290b57cec5SDimitry Andric }
29300b57cec5SDimitry Andric
29310b57cec5SDimitry Andric /// Initialize the per-region scheduling policy.
initPolicy(MachineBasicBlock::iterator Begin,MachineBasicBlock::iterator End,unsigned NumRegionInstrs)29320b57cec5SDimitry Andric void GenericScheduler::initPolicy(MachineBasicBlock::iterator Begin,
29330b57cec5SDimitry Andric MachineBasicBlock::iterator End,
29340b57cec5SDimitry Andric unsigned NumRegionInstrs) {
29350b57cec5SDimitry Andric const MachineFunction &MF = *Begin->getMF();
29360b57cec5SDimitry Andric const TargetLowering *TLI = MF.getSubtarget().getTargetLowering();
29370b57cec5SDimitry Andric
29380b57cec5SDimitry Andric // Avoid setting up the register pressure tracker for small regions to save
29390b57cec5SDimitry Andric // compile time. As a rough heuristic, only track pressure when the number of
29400b57cec5SDimitry Andric // schedulable instructions exceeds half the integer register file.
29410b57cec5SDimitry Andric RegionPolicy.ShouldTrackPressure = true;
29420b57cec5SDimitry Andric for (unsigned VT = MVT::i32; VT > (unsigned)MVT::i1; --VT) {
29430b57cec5SDimitry Andric MVT::SimpleValueType LegalIntVT = (MVT::SimpleValueType)VT;
29440b57cec5SDimitry Andric if (TLI->isTypeLegal(LegalIntVT)) {
29450b57cec5SDimitry Andric unsigned NIntRegs = Context->RegClassInfo->getNumAllocatableRegs(
29460b57cec5SDimitry Andric TLI->getRegClassFor(LegalIntVT));
29470b57cec5SDimitry Andric RegionPolicy.ShouldTrackPressure = NumRegionInstrs > (NIntRegs / 2);
29480b57cec5SDimitry Andric }
29490b57cec5SDimitry Andric }
29500b57cec5SDimitry Andric
29510b57cec5SDimitry Andric // For generic targets, we default to bottom-up, because it's simpler and more
29520b57cec5SDimitry Andric // compile-time optimizations have been implemented in that direction.
29530b57cec5SDimitry Andric RegionPolicy.OnlyBottomUp = true;
29540b57cec5SDimitry Andric
29550b57cec5SDimitry Andric // Allow the subtarget to override default policy.
29560b57cec5SDimitry Andric MF.getSubtarget().overrideSchedPolicy(RegionPolicy, NumRegionInstrs);
29570b57cec5SDimitry Andric
29580b57cec5SDimitry Andric // After subtarget overrides, apply command line options.
29590b57cec5SDimitry Andric if (!EnableRegPressure) {
29600b57cec5SDimitry Andric RegionPolicy.ShouldTrackPressure = false;
29610b57cec5SDimitry Andric RegionPolicy.ShouldTrackLaneMasks = false;
29620b57cec5SDimitry Andric }
29630b57cec5SDimitry Andric
29640b57cec5SDimitry Andric // Check -misched-topdown/bottomup can force or unforce scheduling direction.
29650b57cec5SDimitry Andric // e.g. -misched-bottomup=false allows scheduling in both directions.
29660b57cec5SDimitry Andric assert((!ForceTopDown || !ForceBottomUp) &&
29670b57cec5SDimitry Andric "-misched-topdown incompatible with -misched-bottomup");
29680b57cec5SDimitry Andric if (ForceBottomUp.getNumOccurrences() > 0) {
29690b57cec5SDimitry Andric RegionPolicy.OnlyBottomUp = ForceBottomUp;
29700b57cec5SDimitry Andric if (RegionPolicy.OnlyBottomUp)
29710b57cec5SDimitry Andric RegionPolicy.OnlyTopDown = false;
29720b57cec5SDimitry Andric }
29730b57cec5SDimitry Andric if (ForceTopDown.getNumOccurrences() > 0) {
29740b57cec5SDimitry Andric RegionPolicy.OnlyTopDown = ForceTopDown;
29750b57cec5SDimitry Andric if (RegionPolicy.OnlyTopDown)
29760b57cec5SDimitry Andric RegionPolicy.OnlyBottomUp = false;
29770b57cec5SDimitry Andric }
29780b57cec5SDimitry Andric }
29790b57cec5SDimitry Andric
dumpPolicy() const29800b57cec5SDimitry Andric void GenericScheduler::dumpPolicy() const {
29810b57cec5SDimitry Andric // Cannot completely remove virtual function even in release mode.
29820b57cec5SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
29830b57cec5SDimitry Andric dbgs() << "GenericScheduler RegionPolicy: "
29840b57cec5SDimitry Andric << " ShouldTrackPressure=" << RegionPolicy.ShouldTrackPressure
29850b57cec5SDimitry Andric << " OnlyTopDown=" << RegionPolicy.OnlyTopDown
29860b57cec5SDimitry Andric << " OnlyBottomUp=" << RegionPolicy.OnlyBottomUp
29870b57cec5SDimitry Andric << "\n";
29880b57cec5SDimitry Andric #endif
29890b57cec5SDimitry Andric }
29900b57cec5SDimitry Andric
29910b57cec5SDimitry Andric /// Set IsAcyclicLatencyLimited if the acyclic path is longer than the cyclic
29920b57cec5SDimitry Andric /// critical path by more cycles than it takes to drain the instruction buffer.
29930b57cec5SDimitry Andric /// We estimate an upper bounds on in-flight instructions as:
29940b57cec5SDimitry Andric ///
29950b57cec5SDimitry Andric /// CyclesPerIteration = max( CyclicPath, Loop-Resource-Height )
29960b57cec5SDimitry Andric /// InFlightIterations = AcyclicPath / CyclesPerIteration
29970b57cec5SDimitry Andric /// InFlightResources = InFlightIterations * LoopResources
29980b57cec5SDimitry Andric ///
29990b57cec5SDimitry Andric /// TODO: Check execution resources in addition to IssueCount.
checkAcyclicLatency()30000b57cec5SDimitry Andric void GenericScheduler::checkAcyclicLatency() {
30010b57cec5SDimitry Andric if (Rem.CyclicCritPath == 0 || Rem.CyclicCritPath >= Rem.CriticalPath)
30020b57cec5SDimitry Andric return;
30030b57cec5SDimitry Andric
30040b57cec5SDimitry Andric // Scaled number of cycles per loop iteration.
30050b57cec5SDimitry Andric unsigned IterCount =
30060b57cec5SDimitry Andric std::max(Rem.CyclicCritPath * SchedModel->getLatencyFactor(),
30070b57cec5SDimitry Andric Rem.RemIssueCount);
30080b57cec5SDimitry Andric // Scaled acyclic critical path.
30090b57cec5SDimitry Andric unsigned AcyclicCount = Rem.CriticalPath * SchedModel->getLatencyFactor();
30100b57cec5SDimitry Andric // InFlightCount = (AcyclicPath / IterCycles) * InstrPerLoop
30110b57cec5SDimitry Andric unsigned InFlightCount =
30120b57cec5SDimitry Andric (AcyclicCount * Rem.RemIssueCount + IterCount-1) / IterCount;
30130b57cec5SDimitry Andric unsigned BufferLimit =
30140b57cec5SDimitry Andric SchedModel->getMicroOpBufferSize() * SchedModel->getMicroOpFactor();
30150b57cec5SDimitry Andric
30160b57cec5SDimitry Andric Rem.IsAcyclicLatencyLimited = InFlightCount > BufferLimit;
30170b57cec5SDimitry Andric
30180b57cec5SDimitry Andric LLVM_DEBUG(
30190b57cec5SDimitry Andric dbgs() << "IssueCycles="
30200b57cec5SDimitry Andric << Rem.RemIssueCount / SchedModel->getLatencyFactor() << "c "
30210b57cec5SDimitry Andric << "IterCycles=" << IterCount / SchedModel->getLatencyFactor()
30220b57cec5SDimitry Andric << "c NumIters=" << (AcyclicCount + IterCount - 1) / IterCount
30230b57cec5SDimitry Andric << " InFlight=" << InFlightCount / SchedModel->getMicroOpFactor()
30240b57cec5SDimitry Andric << "m BufferLim=" << SchedModel->getMicroOpBufferSize() << "m\n";
30250b57cec5SDimitry Andric if (Rem.IsAcyclicLatencyLimited) dbgs() << " ACYCLIC LATENCY LIMIT\n");
30260b57cec5SDimitry Andric }
30270b57cec5SDimitry Andric
registerRoots()30280b57cec5SDimitry Andric void GenericScheduler::registerRoots() {
30290b57cec5SDimitry Andric Rem.CriticalPath = DAG->ExitSU.getDepth();
30300b57cec5SDimitry Andric
30310b57cec5SDimitry Andric // Some roots may not feed into ExitSU. Check all of them in case.
30320b57cec5SDimitry Andric for (const SUnit *SU : Bot.Available) {
30330b57cec5SDimitry Andric if (SU->getDepth() > Rem.CriticalPath)
30340b57cec5SDimitry Andric Rem.CriticalPath = SU->getDepth();
30350b57cec5SDimitry Andric }
30360b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Critical Path(GS-RR ): " << Rem.CriticalPath << '\n');
30370b57cec5SDimitry Andric if (DumpCriticalPathLength) {
30380b57cec5SDimitry Andric errs() << "Critical Path(GS-RR ): " << Rem.CriticalPath << " \n";
30390b57cec5SDimitry Andric }
30400b57cec5SDimitry Andric
30410b57cec5SDimitry Andric if (EnableCyclicPath && SchedModel->getMicroOpBufferSize() > 0) {
30420b57cec5SDimitry Andric Rem.CyclicCritPath = DAG->computeCyclicCriticalPath();
30430b57cec5SDimitry Andric checkAcyclicLatency();
30440b57cec5SDimitry Andric }
30450b57cec5SDimitry Andric }
30460b57cec5SDimitry Andric
30470b57cec5SDimitry 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)30480b57cec5SDimitry Andric bool tryPressure(const PressureChange &TryP,
30490b57cec5SDimitry Andric const PressureChange &CandP,
30500b57cec5SDimitry Andric GenericSchedulerBase::SchedCandidate &TryCand,
30510b57cec5SDimitry Andric GenericSchedulerBase::SchedCandidate &Cand,
30520b57cec5SDimitry Andric GenericSchedulerBase::CandReason Reason,
30530b57cec5SDimitry Andric const TargetRegisterInfo *TRI,
30540b57cec5SDimitry Andric const MachineFunction &MF) {
30550b57cec5SDimitry Andric // If one candidate decreases and the other increases, go with it.
30560b57cec5SDimitry Andric // Invalid candidates have UnitInc==0.
30570b57cec5SDimitry Andric if (tryGreater(TryP.getUnitInc() < 0, CandP.getUnitInc() < 0, TryCand, Cand,
30580b57cec5SDimitry Andric Reason)) {
30590b57cec5SDimitry Andric return true;
30600b57cec5SDimitry Andric }
30610b57cec5SDimitry Andric // Do not compare the magnitude of pressure changes between top and bottom
30620b57cec5SDimitry Andric // boundary.
30630b57cec5SDimitry Andric if (Cand.AtTop != TryCand.AtTop)
30640b57cec5SDimitry Andric return false;
30650b57cec5SDimitry Andric
30660b57cec5SDimitry Andric // If both candidates affect the same set in the same boundary, go with the
30670b57cec5SDimitry Andric // smallest increase.
30680b57cec5SDimitry Andric unsigned TryPSet = TryP.getPSetOrMax();
30690b57cec5SDimitry Andric unsigned CandPSet = CandP.getPSetOrMax();
30700b57cec5SDimitry Andric if (TryPSet == CandPSet) {
30710b57cec5SDimitry Andric return tryLess(TryP.getUnitInc(), CandP.getUnitInc(), TryCand, Cand,
30720b57cec5SDimitry Andric Reason);
30730b57cec5SDimitry Andric }
30740b57cec5SDimitry Andric
30750b57cec5SDimitry Andric int TryRank = TryP.isValid() ? TRI->getRegPressureSetScore(MF, TryPSet) :
30760b57cec5SDimitry Andric std::numeric_limits<int>::max();
30770b57cec5SDimitry Andric
30780b57cec5SDimitry Andric int CandRank = CandP.isValid() ? TRI->getRegPressureSetScore(MF, CandPSet) :
30790b57cec5SDimitry Andric std::numeric_limits<int>::max();
30800b57cec5SDimitry Andric
30810b57cec5SDimitry Andric // If the candidates are decreasing pressure, reverse priority.
30820b57cec5SDimitry Andric if (TryP.getUnitInc() < 0)
30830b57cec5SDimitry Andric std::swap(TryRank, CandRank);
30840b57cec5SDimitry Andric return tryGreater(TryRank, CandRank, TryCand, Cand, Reason);
30850b57cec5SDimitry Andric }
30860b57cec5SDimitry Andric
getWeakLeft(const SUnit * SU,bool isTop)30870b57cec5SDimitry Andric unsigned getWeakLeft(const SUnit *SU, bool isTop) {
30880b57cec5SDimitry Andric return (isTop) ? SU->WeakPredsLeft : SU->WeakSuccsLeft;
30890b57cec5SDimitry Andric }
30900b57cec5SDimitry Andric
30910b57cec5SDimitry Andric /// Minimize physical register live ranges. Regalloc wants them adjacent to
30920b57cec5SDimitry Andric /// their physreg def/use.
30930b57cec5SDimitry Andric ///
30940b57cec5SDimitry Andric /// FIXME: This is an unnecessary check on the critical path. Most are root/leaf
30950b57cec5SDimitry Andric /// copies which can be prescheduled. The rest (e.g. x86 MUL) could be bundled
30960b57cec5SDimitry Andric /// with the operation that produces or consumes the physreg. We'll do this when
30970b57cec5SDimitry Andric /// regalloc has support for parallel copies.
biasPhysReg(const SUnit * SU,bool isTop)30980b57cec5SDimitry Andric int biasPhysReg(const SUnit *SU, bool isTop) {
30990b57cec5SDimitry Andric const MachineInstr *MI = SU->getInstr();
31000b57cec5SDimitry Andric
31010b57cec5SDimitry Andric if (MI->isCopy()) {
31020b57cec5SDimitry Andric unsigned ScheduledOper = isTop ? 1 : 0;
31030b57cec5SDimitry Andric unsigned UnscheduledOper = isTop ? 0 : 1;
31040b57cec5SDimitry Andric // If we have already scheduled the physreg produce/consumer, immediately
31050b57cec5SDimitry Andric // schedule the copy.
31068bcb0991SDimitry Andric if (Register::isPhysicalRegister(MI->getOperand(ScheduledOper).getReg()))
31070b57cec5SDimitry Andric return 1;
31080b57cec5SDimitry Andric // If the physreg is at the boundary, defer it. Otherwise schedule it
31090b57cec5SDimitry Andric // immediately to free the dependent. We can hoist the copy later.
31100b57cec5SDimitry Andric bool AtBoundary = isTop ? !SU->NumSuccsLeft : !SU->NumPredsLeft;
31118bcb0991SDimitry Andric if (Register::isPhysicalRegister(MI->getOperand(UnscheduledOper).getReg()))
31120b57cec5SDimitry Andric return AtBoundary ? -1 : 1;
31130b57cec5SDimitry Andric }
31140b57cec5SDimitry Andric
31150b57cec5SDimitry Andric if (MI->isMoveImmediate()) {
31160b57cec5SDimitry Andric // If we have a move immediate and all successors have been assigned, bias
31170b57cec5SDimitry Andric // towards scheduling this later. Make sure all register defs are to
31180b57cec5SDimitry Andric // physical registers.
31190b57cec5SDimitry Andric bool DoBias = true;
31200b57cec5SDimitry Andric for (const MachineOperand &Op : MI->defs()) {
31218bcb0991SDimitry Andric if (Op.isReg() && !Register::isPhysicalRegister(Op.getReg())) {
31220b57cec5SDimitry Andric DoBias = false;
31230b57cec5SDimitry Andric break;
31240b57cec5SDimitry Andric }
31250b57cec5SDimitry Andric }
31260b57cec5SDimitry Andric
31270b57cec5SDimitry Andric if (DoBias)
31280b57cec5SDimitry Andric return isTop ? -1 : 1;
31290b57cec5SDimitry Andric }
31300b57cec5SDimitry Andric
31310b57cec5SDimitry Andric return 0;
31320b57cec5SDimitry Andric }
31330b57cec5SDimitry Andric } // end namespace llvm
31340b57cec5SDimitry Andric
initCandidate(SchedCandidate & Cand,SUnit * SU,bool AtTop,const RegPressureTracker & RPTracker,RegPressureTracker & TempTracker)31350b57cec5SDimitry Andric void GenericScheduler::initCandidate(SchedCandidate &Cand, SUnit *SU,
31360b57cec5SDimitry Andric bool AtTop,
31370b57cec5SDimitry Andric const RegPressureTracker &RPTracker,
31380b57cec5SDimitry Andric RegPressureTracker &TempTracker) {
31390b57cec5SDimitry Andric Cand.SU = SU;
31400b57cec5SDimitry Andric Cand.AtTop = AtTop;
31410b57cec5SDimitry Andric if (DAG->isTrackingPressure()) {
31420b57cec5SDimitry Andric if (AtTop) {
31430b57cec5SDimitry Andric TempTracker.getMaxDownwardPressureDelta(
31440b57cec5SDimitry Andric Cand.SU->getInstr(),
31450b57cec5SDimitry Andric Cand.RPDelta,
31460b57cec5SDimitry Andric DAG->getRegionCriticalPSets(),
31470b57cec5SDimitry Andric DAG->getRegPressure().MaxSetPressure);
31480b57cec5SDimitry Andric } else {
31490b57cec5SDimitry Andric if (VerifyScheduling) {
31500b57cec5SDimitry Andric TempTracker.getMaxUpwardPressureDelta(
31510b57cec5SDimitry Andric Cand.SU->getInstr(),
31520b57cec5SDimitry Andric &DAG->getPressureDiff(Cand.SU),
31530b57cec5SDimitry Andric Cand.RPDelta,
31540b57cec5SDimitry Andric DAG->getRegionCriticalPSets(),
31550b57cec5SDimitry Andric DAG->getRegPressure().MaxSetPressure);
31560b57cec5SDimitry Andric } else {
31570b57cec5SDimitry Andric RPTracker.getUpwardPressureDelta(
31580b57cec5SDimitry Andric Cand.SU->getInstr(),
31590b57cec5SDimitry Andric DAG->getPressureDiff(Cand.SU),
31600b57cec5SDimitry Andric Cand.RPDelta,
31610b57cec5SDimitry Andric DAG->getRegionCriticalPSets(),
31620b57cec5SDimitry Andric DAG->getRegPressure().MaxSetPressure);
31630b57cec5SDimitry Andric }
31640b57cec5SDimitry Andric }
31650b57cec5SDimitry Andric }
31660b57cec5SDimitry Andric LLVM_DEBUG(if (Cand.RPDelta.Excess.isValid()) dbgs()
31670b57cec5SDimitry Andric << " Try SU(" << Cand.SU->NodeNum << ") "
31680b57cec5SDimitry Andric << TRI->getRegPressureSetName(Cand.RPDelta.Excess.getPSet()) << ":"
31690b57cec5SDimitry Andric << Cand.RPDelta.Excess.getUnitInc() << "\n");
31700b57cec5SDimitry Andric }
31710b57cec5SDimitry Andric
31720b57cec5SDimitry Andric /// Apply a set of heuristics to a new candidate. Heuristics are currently
31730b57cec5SDimitry Andric /// hierarchical. This may be more efficient than a graduated cost model because
31740b57cec5SDimitry Andric /// we don't need to evaluate all aspects of the model for each node in the
31750b57cec5SDimitry Andric /// queue. But it's really done to make the heuristics easier to debug and
31760b57cec5SDimitry Andric /// statistically analyze.
31770b57cec5SDimitry Andric ///
31780b57cec5SDimitry Andric /// \param Cand provides the policy and current best candidate.
31790b57cec5SDimitry Andric /// \param TryCand refers to the next SUnit candidate, otherwise uninitialized.
31800b57cec5SDimitry Andric /// \param Zone describes the scheduled zone that we are extending, or nullptr
3181*5f7ddb14SDimitry Andric /// if Cand is from a different zone than TryCand.
3182*5f7ddb14SDimitry Andric /// \return \c true if TryCand is better than Cand (Reason is NOT NoCand)
tryCandidate(SchedCandidate & Cand,SchedCandidate & TryCand,SchedBoundary * Zone) const3183*5f7ddb14SDimitry Andric bool GenericScheduler::tryCandidate(SchedCandidate &Cand,
31840b57cec5SDimitry Andric SchedCandidate &TryCand,
31850b57cec5SDimitry Andric SchedBoundary *Zone) const {
31860b57cec5SDimitry Andric // Initialize the candidate if needed.
31870b57cec5SDimitry Andric if (!Cand.isValid()) {
31880b57cec5SDimitry Andric TryCand.Reason = NodeOrder;
3189*5f7ddb14SDimitry Andric return true;
31900b57cec5SDimitry Andric }
31910b57cec5SDimitry Andric
31920b57cec5SDimitry Andric // Bias PhysReg Defs and copies to their uses and defined respectively.
31930b57cec5SDimitry Andric if (tryGreater(biasPhysReg(TryCand.SU, TryCand.AtTop),
31940b57cec5SDimitry Andric biasPhysReg(Cand.SU, Cand.AtTop), TryCand, Cand, PhysReg))
3195*5f7ddb14SDimitry Andric return TryCand.Reason != NoCand;
31960b57cec5SDimitry Andric
31970b57cec5SDimitry Andric // Avoid exceeding the target's limit.
31980b57cec5SDimitry Andric if (DAG->isTrackingPressure() && tryPressure(TryCand.RPDelta.Excess,
31990b57cec5SDimitry Andric Cand.RPDelta.Excess,
32000b57cec5SDimitry Andric TryCand, Cand, RegExcess, TRI,
32010b57cec5SDimitry Andric DAG->MF))
3202*5f7ddb14SDimitry Andric return TryCand.Reason != NoCand;
32030b57cec5SDimitry Andric
32040b57cec5SDimitry Andric // Avoid increasing the max critical pressure in the scheduled region.
32050b57cec5SDimitry Andric if (DAG->isTrackingPressure() && tryPressure(TryCand.RPDelta.CriticalMax,
32060b57cec5SDimitry Andric Cand.RPDelta.CriticalMax,
32070b57cec5SDimitry Andric TryCand, Cand, RegCritical, TRI,
32080b57cec5SDimitry Andric DAG->MF))
3209*5f7ddb14SDimitry Andric return TryCand.Reason != NoCand;
32100b57cec5SDimitry Andric
32110b57cec5SDimitry Andric // We only compare a subset of features when comparing nodes between
32120b57cec5SDimitry Andric // Top and Bottom boundary. Some properties are simply incomparable, in many
32130b57cec5SDimitry Andric // other instances we should only override the other boundary if something
32140b57cec5SDimitry Andric // is a clear good pick on one boundary. Skip heuristics that are more
32150b57cec5SDimitry Andric // "tie-breaking" in nature.
32160b57cec5SDimitry Andric bool SameBoundary = Zone != nullptr;
32170b57cec5SDimitry Andric if (SameBoundary) {
32180b57cec5SDimitry Andric // For loops that are acyclic path limited, aggressively schedule for
32190b57cec5SDimitry Andric // latency. Within an single cycle, whenever CurrMOps > 0, allow normal
32200b57cec5SDimitry Andric // heuristics to take precedence.
32210b57cec5SDimitry Andric if (Rem.IsAcyclicLatencyLimited && !Zone->getCurrMOps() &&
32220b57cec5SDimitry Andric tryLatency(TryCand, Cand, *Zone))
3223*5f7ddb14SDimitry Andric return TryCand.Reason != NoCand;
32240b57cec5SDimitry Andric
32250b57cec5SDimitry Andric // Prioritize instructions that read unbuffered resources by stall cycles.
32260b57cec5SDimitry Andric if (tryLess(Zone->getLatencyStallCycles(TryCand.SU),
32270b57cec5SDimitry Andric Zone->getLatencyStallCycles(Cand.SU), TryCand, Cand, Stall))
3228*5f7ddb14SDimitry Andric return TryCand.Reason != NoCand;
32290b57cec5SDimitry Andric }
32300b57cec5SDimitry Andric
32310b57cec5SDimitry Andric // Keep clustered nodes together to encourage downstream peephole
32320b57cec5SDimitry Andric // optimizations which may reduce resource requirements.
32330b57cec5SDimitry Andric //
32340b57cec5SDimitry Andric // This is a best effort to set things up for a post-RA pass. Optimizations
32350b57cec5SDimitry Andric // like generating loads of multiple registers should ideally be done within
32360b57cec5SDimitry Andric // the scheduler pass by combining the loads during DAG postprocessing.
32370b57cec5SDimitry Andric const SUnit *CandNextClusterSU =
32380b57cec5SDimitry Andric Cand.AtTop ? DAG->getNextClusterSucc() : DAG->getNextClusterPred();
32390b57cec5SDimitry Andric const SUnit *TryCandNextClusterSU =
32400b57cec5SDimitry Andric TryCand.AtTop ? DAG->getNextClusterSucc() : DAG->getNextClusterPred();
32410b57cec5SDimitry Andric if (tryGreater(TryCand.SU == TryCandNextClusterSU,
32420b57cec5SDimitry Andric Cand.SU == CandNextClusterSU,
32430b57cec5SDimitry Andric TryCand, Cand, Cluster))
3244*5f7ddb14SDimitry Andric return TryCand.Reason != NoCand;
32450b57cec5SDimitry Andric
32460b57cec5SDimitry Andric if (SameBoundary) {
32470b57cec5SDimitry Andric // Weak edges are for clustering and other constraints.
32480b57cec5SDimitry Andric if (tryLess(getWeakLeft(TryCand.SU, TryCand.AtTop),
32490b57cec5SDimitry Andric getWeakLeft(Cand.SU, Cand.AtTop),
32500b57cec5SDimitry Andric TryCand, Cand, Weak))
3251*5f7ddb14SDimitry Andric return TryCand.Reason != NoCand;
32520b57cec5SDimitry Andric }
32530b57cec5SDimitry Andric
32540b57cec5SDimitry Andric // Avoid increasing the max pressure of the entire region.
32550b57cec5SDimitry Andric if (DAG->isTrackingPressure() && tryPressure(TryCand.RPDelta.CurrentMax,
32560b57cec5SDimitry Andric Cand.RPDelta.CurrentMax,
32570b57cec5SDimitry Andric TryCand, Cand, RegMax, TRI,
32580b57cec5SDimitry Andric DAG->MF))
3259*5f7ddb14SDimitry Andric return TryCand.Reason != NoCand;
32600b57cec5SDimitry Andric
32610b57cec5SDimitry Andric if (SameBoundary) {
32620b57cec5SDimitry Andric // Avoid critical resource consumption and balance the schedule.
32630b57cec5SDimitry Andric TryCand.initResourceDelta(DAG, SchedModel);
32640b57cec5SDimitry Andric if (tryLess(TryCand.ResDelta.CritResources, Cand.ResDelta.CritResources,
32650b57cec5SDimitry Andric TryCand, Cand, ResourceReduce))
3266*5f7ddb14SDimitry Andric return TryCand.Reason != NoCand;
32670b57cec5SDimitry Andric if (tryGreater(TryCand.ResDelta.DemandedResources,
32680b57cec5SDimitry Andric Cand.ResDelta.DemandedResources,
32690b57cec5SDimitry Andric TryCand, Cand, ResourceDemand))
3270*5f7ddb14SDimitry Andric return TryCand.Reason != NoCand;
32710b57cec5SDimitry Andric
32720b57cec5SDimitry Andric // Avoid serializing long latency dependence chains.
32730b57cec5SDimitry Andric // For acyclic path limited loops, latency was already checked above.
32740b57cec5SDimitry Andric if (!RegionPolicy.DisableLatencyHeuristic && TryCand.Policy.ReduceLatency &&
32750b57cec5SDimitry Andric !Rem.IsAcyclicLatencyLimited && tryLatency(TryCand, Cand, *Zone))
3276*5f7ddb14SDimitry Andric return TryCand.Reason != NoCand;
32770b57cec5SDimitry Andric
32780b57cec5SDimitry Andric // Fall through to original instruction order.
32790b57cec5SDimitry Andric if ((Zone->isTop() && TryCand.SU->NodeNum < Cand.SU->NodeNum)
32800b57cec5SDimitry Andric || (!Zone->isTop() && TryCand.SU->NodeNum > Cand.SU->NodeNum)) {
32810b57cec5SDimitry Andric TryCand.Reason = NodeOrder;
3282*5f7ddb14SDimitry Andric return true;
32830b57cec5SDimitry Andric }
32840b57cec5SDimitry Andric }
3285*5f7ddb14SDimitry Andric
3286*5f7ddb14SDimitry Andric return false;
32870b57cec5SDimitry Andric }
32880b57cec5SDimitry Andric
32890b57cec5SDimitry Andric /// Pick the best candidate from the queue.
32900b57cec5SDimitry Andric ///
32910b57cec5SDimitry Andric /// TODO: getMaxPressureDelta results can be mostly cached for each SUnit during
32920b57cec5SDimitry Andric /// DAG building. To adjust for the current scheduling location we need to
32930b57cec5SDimitry Andric /// maintain the number of vreg uses remaining to be top-scheduled.
pickNodeFromQueue(SchedBoundary & Zone,const CandPolicy & ZonePolicy,const RegPressureTracker & RPTracker,SchedCandidate & Cand)32940b57cec5SDimitry Andric void GenericScheduler::pickNodeFromQueue(SchedBoundary &Zone,
32950b57cec5SDimitry Andric const CandPolicy &ZonePolicy,
32960b57cec5SDimitry Andric const RegPressureTracker &RPTracker,
32970b57cec5SDimitry Andric SchedCandidate &Cand) {
32980b57cec5SDimitry Andric // getMaxPressureDelta temporarily modifies the tracker.
32990b57cec5SDimitry Andric RegPressureTracker &TempTracker = const_cast<RegPressureTracker&>(RPTracker);
33000b57cec5SDimitry Andric
33010b57cec5SDimitry Andric ReadyQueue &Q = Zone.Available;
33020b57cec5SDimitry Andric for (SUnit *SU : Q) {
33030b57cec5SDimitry Andric
33040b57cec5SDimitry Andric SchedCandidate TryCand(ZonePolicy);
33050b57cec5SDimitry Andric initCandidate(TryCand, SU, Zone.isTop(), RPTracker, TempTracker);
33060b57cec5SDimitry Andric // Pass SchedBoundary only when comparing nodes from the same boundary.
33070b57cec5SDimitry Andric SchedBoundary *ZoneArg = Cand.AtTop == TryCand.AtTop ? &Zone : nullptr;
3308*5f7ddb14SDimitry Andric if (tryCandidate(Cand, TryCand, ZoneArg)) {
33090b57cec5SDimitry Andric // Initialize resource delta if needed in case future heuristics query it.
33100b57cec5SDimitry Andric if (TryCand.ResDelta == SchedResourceDelta())
33110b57cec5SDimitry Andric TryCand.initResourceDelta(DAG, SchedModel);
33120b57cec5SDimitry Andric Cand.setBest(TryCand);
33130b57cec5SDimitry Andric LLVM_DEBUG(traceCandidate(Cand));
33140b57cec5SDimitry Andric }
33150b57cec5SDimitry Andric }
33160b57cec5SDimitry Andric }
33170b57cec5SDimitry Andric
33180b57cec5SDimitry Andric /// Pick the best candidate node from either the top or bottom queue.
pickNodeBidirectional(bool & IsTopNode)33190b57cec5SDimitry Andric SUnit *GenericScheduler::pickNodeBidirectional(bool &IsTopNode) {
33200b57cec5SDimitry Andric // Schedule as far as possible in the direction of no choice. This is most
33210b57cec5SDimitry Andric // efficient, but also provides the best heuristics for CriticalPSets.
33220b57cec5SDimitry Andric if (SUnit *SU = Bot.pickOnlyChoice()) {
33230b57cec5SDimitry Andric IsTopNode = false;
33240b57cec5SDimitry Andric tracePick(Only1, false);
33250b57cec5SDimitry Andric return SU;
33260b57cec5SDimitry Andric }
33270b57cec5SDimitry Andric if (SUnit *SU = Top.pickOnlyChoice()) {
33280b57cec5SDimitry Andric IsTopNode = true;
33290b57cec5SDimitry Andric tracePick(Only1, true);
33300b57cec5SDimitry Andric return SU;
33310b57cec5SDimitry Andric }
33320b57cec5SDimitry Andric // Set the bottom-up policy based on the state of the current bottom zone and
33330b57cec5SDimitry Andric // the instructions outside the zone, including the top zone.
33340b57cec5SDimitry Andric CandPolicy BotPolicy;
33350b57cec5SDimitry Andric setPolicy(BotPolicy, /*IsPostRA=*/false, Bot, &Top);
33360b57cec5SDimitry Andric // Set the top-down policy based on the state of the current top zone and
33370b57cec5SDimitry Andric // the instructions outside the zone, including the bottom zone.
33380b57cec5SDimitry Andric CandPolicy TopPolicy;
33390b57cec5SDimitry Andric setPolicy(TopPolicy, /*IsPostRA=*/false, Top, &Bot);
33400b57cec5SDimitry Andric
33410b57cec5SDimitry Andric // See if BotCand is still valid (because we previously scheduled from Top).
33420b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Picking from Bot:\n");
33430b57cec5SDimitry Andric if (!BotCand.isValid() || BotCand.SU->isScheduled ||
33440b57cec5SDimitry Andric BotCand.Policy != BotPolicy) {
33450b57cec5SDimitry Andric BotCand.reset(CandPolicy());
33460b57cec5SDimitry Andric pickNodeFromQueue(Bot, BotPolicy, DAG->getBotRPTracker(), BotCand);
33470b57cec5SDimitry Andric assert(BotCand.Reason != NoCand && "failed to find the first candidate");
33480b57cec5SDimitry Andric } else {
33490b57cec5SDimitry Andric LLVM_DEBUG(traceCandidate(BotCand));
33500b57cec5SDimitry Andric #ifndef NDEBUG
33510b57cec5SDimitry Andric if (VerifyScheduling) {
33520b57cec5SDimitry Andric SchedCandidate TCand;
33530b57cec5SDimitry Andric TCand.reset(CandPolicy());
33540b57cec5SDimitry Andric pickNodeFromQueue(Bot, BotPolicy, DAG->getBotRPTracker(), TCand);
33550b57cec5SDimitry Andric assert(TCand.SU == BotCand.SU &&
33560b57cec5SDimitry Andric "Last pick result should correspond to re-picking right now");
33570b57cec5SDimitry Andric }
33580b57cec5SDimitry Andric #endif
33590b57cec5SDimitry Andric }
33600b57cec5SDimitry Andric
33610b57cec5SDimitry Andric // Check if the top Q has a better candidate.
33620b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Picking from Top:\n");
33630b57cec5SDimitry Andric if (!TopCand.isValid() || TopCand.SU->isScheduled ||
33640b57cec5SDimitry Andric TopCand.Policy != TopPolicy) {
33650b57cec5SDimitry Andric TopCand.reset(CandPolicy());
33660b57cec5SDimitry Andric pickNodeFromQueue(Top, TopPolicy, DAG->getTopRPTracker(), TopCand);
33670b57cec5SDimitry Andric assert(TopCand.Reason != NoCand && "failed to find the first candidate");
33680b57cec5SDimitry Andric } else {
33690b57cec5SDimitry Andric LLVM_DEBUG(traceCandidate(TopCand));
33700b57cec5SDimitry Andric #ifndef NDEBUG
33710b57cec5SDimitry Andric if (VerifyScheduling) {
33720b57cec5SDimitry Andric SchedCandidate TCand;
33730b57cec5SDimitry Andric TCand.reset(CandPolicy());
33740b57cec5SDimitry Andric pickNodeFromQueue(Top, TopPolicy, DAG->getTopRPTracker(), TCand);
33750b57cec5SDimitry Andric assert(TCand.SU == TopCand.SU &&
33760b57cec5SDimitry Andric "Last pick result should correspond to re-picking right now");
33770b57cec5SDimitry Andric }
33780b57cec5SDimitry Andric #endif
33790b57cec5SDimitry Andric }
33800b57cec5SDimitry Andric
33810b57cec5SDimitry Andric // Pick best from BotCand and TopCand.
33820b57cec5SDimitry Andric assert(BotCand.isValid());
33830b57cec5SDimitry Andric assert(TopCand.isValid());
33840b57cec5SDimitry Andric SchedCandidate Cand = BotCand;
33850b57cec5SDimitry Andric TopCand.Reason = NoCand;
3386*5f7ddb14SDimitry Andric if (tryCandidate(Cand, TopCand, nullptr)) {
33870b57cec5SDimitry Andric Cand.setBest(TopCand);
33880b57cec5SDimitry Andric LLVM_DEBUG(traceCandidate(Cand));
33890b57cec5SDimitry Andric }
33900b57cec5SDimitry Andric
33910b57cec5SDimitry Andric IsTopNode = Cand.AtTop;
33920b57cec5SDimitry Andric tracePick(Cand);
33930b57cec5SDimitry Andric return Cand.SU;
33940b57cec5SDimitry Andric }
33950b57cec5SDimitry Andric
33960b57cec5SDimitry Andric /// Pick the best node to balance the schedule. Implements MachineSchedStrategy.
pickNode(bool & IsTopNode)33970b57cec5SDimitry Andric SUnit *GenericScheduler::pickNode(bool &IsTopNode) {
33980b57cec5SDimitry Andric if (DAG->top() == DAG->bottom()) {
33990b57cec5SDimitry Andric assert(Top.Available.empty() && Top.Pending.empty() &&
34000b57cec5SDimitry Andric Bot.Available.empty() && Bot.Pending.empty() && "ReadyQ garbage");
34010b57cec5SDimitry Andric return nullptr;
34020b57cec5SDimitry Andric }
34030b57cec5SDimitry Andric SUnit *SU;
34040b57cec5SDimitry Andric do {
34050b57cec5SDimitry Andric if (RegionPolicy.OnlyTopDown) {
34060b57cec5SDimitry Andric SU = Top.pickOnlyChoice();
34070b57cec5SDimitry Andric if (!SU) {
34080b57cec5SDimitry Andric CandPolicy NoPolicy;
34090b57cec5SDimitry Andric TopCand.reset(NoPolicy);
34100b57cec5SDimitry Andric pickNodeFromQueue(Top, NoPolicy, DAG->getTopRPTracker(), TopCand);
34110b57cec5SDimitry Andric assert(TopCand.Reason != NoCand && "failed to find a candidate");
34120b57cec5SDimitry Andric tracePick(TopCand);
34130b57cec5SDimitry Andric SU = TopCand.SU;
34140b57cec5SDimitry Andric }
34150b57cec5SDimitry Andric IsTopNode = true;
34160b57cec5SDimitry Andric } else if (RegionPolicy.OnlyBottomUp) {
34170b57cec5SDimitry Andric SU = Bot.pickOnlyChoice();
34180b57cec5SDimitry Andric if (!SU) {
34190b57cec5SDimitry Andric CandPolicy NoPolicy;
34200b57cec5SDimitry Andric BotCand.reset(NoPolicy);
34210b57cec5SDimitry Andric pickNodeFromQueue(Bot, NoPolicy, DAG->getBotRPTracker(), BotCand);
34220b57cec5SDimitry Andric assert(BotCand.Reason != NoCand && "failed to find a candidate");
34230b57cec5SDimitry Andric tracePick(BotCand);
34240b57cec5SDimitry Andric SU = BotCand.SU;
34250b57cec5SDimitry Andric }
34260b57cec5SDimitry Andric IsTopNode = false;
34270b57cec5SDimitry Andric } else {
34280b57cec5SDimitry Andric SU = pickNodeBidirectional(IsTopNode);
34290b57cec5SDimitry Andric }
34300b57cec5SDimitry Andric } while (SU->isScheduled);
34310b57cec5SDimitry Andric
34320b57cec5SDimitry Andric if (SU->isTopReady())
34330b57cec5SDimitry Andric Top.removeReady(SU);
34340b57cec5SDimitry Andric if (SU->isBottomReady())
34350b57cec5SDimitry Andric Bot.removeReady(SU);
34360b57cec5SDimitry Andric
34370b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Scheduling SU(" << SU->NodeNum << ") "
34380b57cec5SDimitry Andric << *SU->getInstr());
34390b57cec5SDimitry Andric return SU;
34400b57cec5SDimitry Andric }
34410b57cec5SDimitry Andric
reschedulePhysReg(SUnit * SU,bool isTop)34420b57cec5SDimitry Andric void GenericScheduler::reschedulePhysReg(SUnit *SU, bool isTop) {
34430b57cec5SDimitry Andric MachineBasicBlock::iterator InsertPos = SU->getInstr();
34440b57cec5SDimitry Andric if (!isTop)
34450b57cec5SDimitry Andric ++InsertPos;
34460b57cec5SDimitry Andric SmallVectorImpl<SDep> &Deps = isTop ? SU->Preds : SU->Succs;
34470b57cec5SDimitry Andric
34480b57cec5SDimitry Andric // Find already scheduled copies with a single physreg dependence and move
34490b57cec5SDimitry Andric // them just above the scheduled instruction.
34500b57cec5SDimitry Andric for (SDep &Dep : Deps) {
34518bcb0991SDimitry Andric if (Dep.getKind() != SDep::Data ||
34528bcb0991SDimitry Andric !Register::isPhysicalRegister(Dep.getReg()))
34530b57cec5SDimitry Andric continue;
34540b57cec5SDimitry Andric SUnit *DepSU = Dep.getSUnit();
34550b57cec5SDimitry Andric if (isTop ? DepSU->Succs.size() > 1 : DepSU->Preds.size() > 1)
34560b57cec5SDimitry Andric continue;
34570b57cec5SDimitry Andric MachineInstr *Copy = DepSU->getInstr();
34580b57cec5SDimitry Andric if (!Copy->isCopy() && !Copy->isMoveImmediate())
34590b57cec5SDimitry Andric continue;
34600b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " Rescheduling physreg copy ";
34610b57cec5SDimitry Andric DAG->dumpNode(*Dep.getSUnit()));
34620b57cec5SDimitry Andric DAG->moveInstruction(Copy, InsertPos);
34630b57cec5SDimitry Andric }
34640b57cec5SDimitry Andric }
34650b57cec5SDimitry Andric
34660b57cec5SDimitry Andric /// Update the scheduler's state after scheduling a node. This is the same node
34670b57cec5SDimitry Andric /// that was just returned by pickNode(). However, ScheduleDAGMILive needs to
34680b57cec5SDimitry Andric /// update it's state based on the current cycle before MachineSchedStrategy
34690b57cec5SDimitry Andric /// does.
34700b57cec5SDimitry Andric ///
34710b57cec5SDimitry Andric /// FIXME: Eventually, we may bundle physreg copies rather than rescheduling
34720b57cec5SDimitry Andric /// them here. See comments in biasPhysReg.
schedNode(SUnit * SU,bool IsTopNode)34730b57cec5SDimitry Andric void GenericScheduler::schedNode(SUnit *SU, bool IsTopNode) {
34740b57cec5SDimitry Andric if (IsTopNode) {
34750b57cec5SDimitry Andric SU->TopReadyCycle = std::max(SU->TopReadyCycle, Top.getCurrCycle());
34760b57cec5SDimitry Andric Top.bumpNode(SU);
34770b57cec5SDimitry Andric if (SU->hasPhysRegUses)
34780b57cec5SDimitry Andric reschedulePhysReg(SU, true);
34790b57cec5SDimitry Andric } else {
34800b57cec5SDimitry Andric SU->BotReadyCycle = std::max(SU->BotReadyCycle, Bot.getCurrCycle());
34810b57cec5SDimitry Andric Bot.bumpNode(SU);
34820b57cec5SDimitry Andric if (SU->hasPhysRegDefs)
34830b57cec5SDimitry Andric reschedulePhysReg(SU, false);
34840b57cec5SDimitry Andric }
34850b57cec5SDimitry Andric }
34860b57cec5SDimitry Andric
34870b57cec5SDimitry Andric /// Create the standard converging machine scheduler. This will be used as the
34880b57cec5SDimitry Andric /// default scheduler if the target does not set a default.
createGenericSchedLive(MachineSchedContext * C)34890b57cec5SDimitry Andric ScheduleDAGMILive *llvm::createGenericSchedLive(MachineSchedContext *C) {
34900b57cec5SDimitry Andric ScheduleDAGMILive *DAG =
34918bcb0991SDimitry Andric new ScheduleDAGMILive(C, std::make_unique<GenericScheduler>(C));
34920b57cec5SDimitry Andric // Register DAG post-processors.
34930b57cec5SDimitry Andric //
34940b57cec5SDimitry Andric // FIXME: extend the mutation API to allow earlier mutations to instantiate
34950b57cec5SDimitry Andric // data and pass it to later mutations. Have a single mutation that gathers
34960b57cec5SDimitry Andric // the interesting nodes in one pass.
34970b57cec5SDimitry Andric DAG->addMutation(createCopyConstrainDAGMutation(DAG->TII, DAG->TRI));
34980b57cec5SDimitry Andric return DAG;
34990b57cec5SDimitry Andric }
35000b57cec5SDimitry Andric
createConvergingSched(MachineSchedContext * C)3501af732203SDimitry Andric static ScheduleDAGInstrs *createConvergingSched(MachineSchedContext *C) {
35020b57cec5SDimitry Andric return createGenericSchedLive(C);
35030b57cec5SDimitry Andric }
35040b57cec5SDimitry Andric
35050b57cec5SDimitry Andric static MachineSchedRegistry
35060b57cec5SDimitry Andric GenericSchedRegistry("converge", "Standard converging scheduler.",
3507af732203SDimitry Andric createConvergingSched);
35080b57cec5SDimitry Andric
35090b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
35100b57cec5SDimitry Andric // PostGenericScheduler - Generic PostRA implementation of MachineSchedStrategy.
35110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
35120b57cec5SDimitry Andric
initialize(ScheduleDAGMI * Dag)35130b57cec5SDimitry Andric void PostGenericScheduler::initialize(ScheduleDAGMI *Dag) {
35140b57cec5SDimitry Andric DAG = Dag;
35150b57cec5SDimitry Andric SchedModel = DAG->getSchedModel();
35160b57cec5SDimitry Andric TRI = DAG->TRI;
35170b57cec5SDimitry Andric
35180b57cec5SDimitry Andric Rem.init(DAG, SchedModel);
35190b57cec5SDimitry Andric Top.init(DAG, SchedModel, &Rem);
35200b57cec5SDimitry Andric BotRoots.clear();
35210b57cec5SDimitry Andric
35220b57cec5SDimitry Andric // Initialize the HazardRecognizers. If itineraries don't exist, are empty,
35230b57cec5SDimitry Andric // or are disabled, then these HazardRecs will be disabled.
35240b57cec5SDimitry Andric const InstrItineraryData *Itin = SchedModel->getInstrItineraries();
35250b57cec5SDimitry Andric if (!Top.HazardRec) {
35260b57cec5SDimitry Andric Top.HazardRec =
35270b57cec5SDimitry Andric DAG->MF.getSubtarget().getInstrInfo()->CreateTargetMIHazardRecognizer(
35280b57cec5SDimitry Andric Itin, DAG);
35290b57cec5SDimitry Andric }
35300b57cec5SDimitry Andric }
35310b57cec5SDimitry Andric
registerRoots()35320b57cec5SDimitry Andric void PostGenericScheduler::registerRoots() {
35330b57cec5SDimitry Andric Rem.CriticalPath = DAG->ExitSU.getDepth();
35340b57cec5SDimitry Andric
35350b57cec5SDimitry Andric // Some roots may not feed into ExitSU. Check all of them in case.
35360b57cec5SDimitry Andric for (const SUnit *SU : BotRoots) {
35370b57cec5SDimitry Andric if (SU->getDepth() > Rem.CriticalPath)
35380b57cec5SDimitry Andric Rem.CriticalPath = SU->getDepth();
35390b57cec5SDimitry Andric }
35400b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Critical Path: (PGS-RR) " << Rem.CriticalPath << '\n');
35410b57cec5SDimitry Andric if (DumpCriticalPathLength) {
35420b57cec5SDimitry Andric errs() << "Critical Path(PGS-RR ): " << Rem.CriticalPath << " \n";
35430b57cec5SDimitry Andric }
35440b57cec5SDimitry Andric }
35450b57cec5SDimitry Andric
35460b57cec5SDimitry Andric /// Apply a set of heuristics to a new candidate for PostRA scheduling.
35470b57cec5SDimitry Andric ///
35480b57cec5SDimitry Andric /// \param Cand provides the policy and current best candidate.
35490b57cec5SDimitry Andric /// \param TryCand refers to the next SUnit candidate, otherwise uninitialized.
3550*5f7ddb14SDimitry Andric /// \return \c true if TryCand is better than Cand (Reason is NOT NoCand)
tryCandidate(SchedCandidate & Cand,SchedCandidate & TryCand)3551*5f7ddb14SDimitry Andric bool PostGenericScheduler::tryCandidate(SchedCandidate &Cand,
35520b57cec5SDimitry Andric SchedCandidate &TryCand) {
35530b57cec5SDimitry Andric // Initialize the candidate if needed.
35540b57cec5SDimitry Andric if (!Cand.isValid()) {
35550b57cec5SDimitry Andric TryCand.Reason = NodeOrder;
3556*5f7ddb14SDimitry Andric return true;
35570b57cec5SDimitry Andric }
35580b57cec5SDimitry Andric
35590b57cec5SDimitry Andric // Prioritize instructions that read unbuffered resources by stall cycles.
35600b57cec5SDimitry Andric if (tryLess(Top.getLatencyStallCycles(TryCand.SU),
35610b57cec5SDimitry Andric Top.getLatencyStallCycles(Cand.SU), TryCand, Cand, Stall))
3562*5f7ddb14SDimitry Andric return TryCand.Reason != NoCand;
35630b57cec5SDimitry Andric
35640b57cec5SDimitry Andric // Keep clustered nodes together.
35650b57cec5SDimitry Andric if (tryGreater(TryCand.SU == DAG->getNextClusterSucc(),
35660b57cec5SDimitry Andric Cand.SU == DAG->getNextClusterSucc(),
35670b57cec5SDimitry Andric TryCand, Cand, Cluster))
3568*5f7ddb14SDimitry Andric return TryCand.Reason != NoCand;
35690b57cec5SDimitry Andric
35700b57cec5SDimitry Andric // Avoid critical resource consumption and balance the schedule.
35710b57cec5SDimitry Andric if (tryLess(TryCand.ResDelta.CritResources, Cand.ResDelta.CritResources,
35720b57cec5SDimitry Andric TryCand, Cand, ResourceReduce))
3573*5f7ddb14SDimitry Andric return TryCand.Reason != NoCand;
35740b57cec5SDimitry Andric if (tryGreater(TryCand.ResDelta.DemandedResources,
35750b57cec5SDimitry Andric Cand.ResDelta.DemandedResources,
35760b57cec5SDimitry Andric TryCand, Cand, ResourceDemand))
3577*5f7ddb14SDimitry Andric return TryCand.Reason != NoCand;
35780b57cec5SDimitry Andric
35790b57cec5SDimitry Andric // Avoid serializing long latency dependence chains.
35800b57cec5SDimitry Andric if (Cand.Policy.ReduceLatency && tryLatency(TryCand, Cand, Top)) {
3581*5f7ddb14SDimitry Andric return TryCand.Reason != NoCand;
35820b57cec5SDimitry Andric }
35830b57cec5SDimitry Andric
35840b57cec5SDimitry Andric // Fall through to original instruction order.
3585*5f7ddb14SDimitry Andric if (TryCand.SU->NodeNum < Cand.SU->NodeNum) {
35860b57cec5SDimitry Andric TryCand.Reason = NodeOrder;
3587*5f7ddb14SDimitry Andric return true;
3588*5f7ddb14SDimitry Andric }
3589*5f7ddb14SDimitry Andric
3590*5f7ddb14SDimitry Andric return false;
35910b57cec5SDimitry Andric }
35920b57cec5SDimitry Andric
pickNodeFromQueue(SchedCandidate & Cand)35930b57cec5SDimitry Andric void PostGenericScheduler::pickNodeFromQueue(SchedCandidate &Cand) {
35940b57cec5SDimitry Andric ReadyQueue &Q = Top.Available;
35950b57cec5SDimitry Andric for (SUnit *SU : Q) {
35960b57cec5SDimitry Andric SchedCandidate TryCand(Cand.Policy);
35970b57cec5SDimitry Andric TryCand.SU = SU;
35980b57cec5SDimitry Andric TryCand.AtTop = true;
35990b57cec5SDimitry Andric TryCand.initResourceDelta(DAG, SchedModel);
3600*5f7ddb14SDimitry Andric if (tryCandidate(Cand, TryCand)) {
36010b57cec5SDimitry Andric Cand.setBest(TryCand);
36020b57cec5SDimitry Andric LLVM_DEBUG(traceCandidate(Cand));
36030b57cec5SDimitry Andric }
36040b57cec5SDimitry Andric }
36050b57cec5SDimitry Andric }
36060b57cec5SDimitry Andric
36070b57cec5SDimitry Andric /// Pick the next node to schedule.
pickNode(bool & IsTopNode)36080b57cec5SDimitry Andric SUnit *PostGenericScheduler::pickNode(bool &IsTopNode) {
36090b57cec5SDimitry Andric if (DAG->top() == DAG->bottom()) {
36100b57cec5SDimitry Andric assert(Top.Available.empty() && Top.Pending.empty() && "ReadyQ garbage");
36110b57cec5SDimitry Andric return nullptr;
36120b57cec5SDimitry Andric }
36130b57cec5SDimitry Andric SUnit *SU;
36140b57cec5SDimitry Andric do {
36150b57cec5SDimitry Andric SU = Top.pickOnlyChoice();
36160b57cec5SDimitry Andric if (SU) {
36170b57cec5SDimitry Andric tracePick(Only1, true);
36180b57cec5SDimitry Andric } else {
36190b57cec5SDimitry Andric CandPolicy NoPolicy;
36200b57cec5SDimitry Andric SchedCandidate TopCand(NoPolicy);
36210b57cec5SDimitry Andric // Set the top-down policy based on the state of the current top zone and
36220b57cec5SDimitry Andric // the instructions outside the zone, including the bottom zone.
36230b57cec5SDimitry Andric setPolicy(TopCand.Policy, /*IsPostRA=*/true, Top, nullptr);
36240b57cec5SDimitry Andric pickNodeFromQueue(TopCand);
36250b57cec5SDimitry Andric assert(TopCand.Reason != NoCand && "failed to find a candidate");
36260b57cec5SDimitry Andric tracePick(TopCand);
36270b57cec5SDimitry Andric SU = TopCand.SU;
36280b57cec5SDimitry Andric }
36290b57cec5SDimitry Andric } while (SU->isScheduled);
36300b57cec5SDimitry Andric
36310b57cec5SDimitry Andric IsTopNode = true;
36320b57cec5SDimitry Andric Top.removeReady(SU);
36330b57cec5SDimitry Andric
36340b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Scheduling SU(" << SU->NodeNum << ") "
36350b57cec5SDimitry Andric << *SU->getInstr());
36360b57cec5SDimitry Andric return SU;
36370b57cec5SDimitry Andric }
36380b57cec5SDimitry Andric
36390b57cec5SDimitry Andric /// Called after ScheduleDAGMI has scheduled an instruction and updated
36400b57cec5SDimitry Andric /// scheduled/remaining flags in the DAG nodes.
schedNode(SUnit * SU,bool IsTopNode)36410b57cec5SDimitry Andric void PostGenericScheduler::schedNode(SUnit *SU, bool IsTopNode) {
36420b57cec5SDimitry Andric SU->TopReadyCycle = std::max(SU->TopReadyCycle, Top.getCurrCycle());
36430b57cec5SDimitry Andric Top.bumpNode(SU);
36440b57cec5SDimitry Andric }
36450b57cec5SDimitry Andric
createGenericSchedPostRA(MachineSchedContext * C)36460b57cec5SDimitry Andric ScheduleDAGMI *llvm::createGenericSchedPostRA(MachineSchedContext *C) {
36478bcb0991SDimitry Andric return new ScheduleDAGMI(C, std::make_unique<PostGenericScheduler>(C),
36480b57cec5SDimitry Andric /*RemoveKillFlags=*/true);
36490b57cec5SDimitry Andric }
36500b57cec5SDimitry Andric
36510b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
36520b57cec5SDimitry Andric // ILP Scheduler. Currently for experimental analysis of heuristics.
36530b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
36540b57cec5SDimitry Andric
36550b57cec5SDimitry Andric namespace {
36560b57cec5SDimitry Andric
36570b57cec5SDimitry Andric /// Order nodes by the ILP metric.
36580b57cec5SDimitry Andric struct ILPOrder {
36590b57cec5SDimitry Andric const SchedDFSResult *DFSResult = nullptr;
36600b57cec5SDimitry Andric const BitVector *ScheduledTrees = nullptr;
36610b57cec5SDimitry Andric bool MaximizeILP;
36620b57cec5SDimitry Andric
ILPOrder__anonde6daefc0511::ILPOrder36630b57cec5SDimitry Andric ILPOrder(bool MaxILP) : MaximizeILP(MaxILP) {}
36640b57cec5SDimitry Andric
36650b57cec5SDimitry Andric /// Apply a less-than relation on node priority.
36660b57cec5SDimitry Andric ///
36670b57cec5SDimitry Andric /// (Return true if A comes after B in the Q.)
operator ()__anonde6daefc0511::ILPOrder36680b57cec5SDimitry Andric bool operator()(const SUnit *A, const SUnit *B) const {
36690b57cec5SDimitry Andric unsigned SchedTreeA = DFSResult->getSubtreeID(A);
36700b57cec5SDimitry Andric unsigned SchedTreeB = DFSResult->getSubtreeID(B);
36710b57cec5SDimitry Andric if (SchedTreeA != SchedTreeB) {
36720b57cec5SDimitry Andric // Unscheduled trees have lower priority.
36730b57cec5SDimitry Andric if (ScheduledTrees->test(SchedTreeA) != ScheduledTrees->test(SchedTreeB))
36740b57cec5SDimitry Andric return ScheduledTrees->test(SchedTreeB);
36750b57cec5SDimitry Andric
36760b57cec5SDimitry Andric // Trees with shallower connections have have lower priority.
36770b57cec5SDimitry Andric if (DFSResult->getSubtreeLevel(SchedTreeA)
36780b57cec5SDimitry Andric != DFSResult->getSubtreeLevel(SchedTreeB)) {
36790b57cec5SDimitry Andric return DFSResult->getSubtreeLevel(SchedTreeA)
36800b57cec5SDimitry Andric < DFSResult->getSubtreeLevel(SchedTreeB);
36810b57cec5SDimitry Andric }
36820b57cec5SDimitry Andric }
36830b57cec5SDimitry Andric if (MaximizeILP)
36840b57cec5SDimitry Andric return DFSResult->getILP(A) < DFSResult->getILP(B);
36850b57cec5SDimitry Andric else
36860b57cec5SDimitry Andric return DFSResult->getILP(A) > DFSResult->getILP(B);
36870b57cec5SDimitry Andric }
36880b57cec5SDimitry Andric };
36890b57cec5SDimitry Andric
36900b57cec5SDimitry Andric /// Schedule based on the ILP metric.
36910b57cec5SDimitry Andric class ILPScheduler : public MachineSchedStrategy {
36920b57cec5SDimitry Andric ScheduleDAGMILive *DAG = nullptr;
36930b57cec5SDimitry Andric ILPOrder Cmp;
36940b57cec5SDimitry Andric
36950b57cec5SDimitry Andric std::vector<SUnit*> ReadyQ;
36960b57cec5SDimitry Andric
36970b57cec5SDimitry Andric public:
ILPScheduler(bool MaximizeILP)36980b57cec5SDimitry Andric ILPScheduler(bool MaximizeILP) : Cmp(MaximizeILP) {}
36990b57cec5SDimitry Andric
initialize(ScheduleDAGMI * dag)37000b57cec5SDimitry Andric void initialize(ScheduleDAGMI *dag) override {
37010b57cec5SDimitry Andric assert(dag->hasVRegLiveness() && "ILPScheduler needs vreg liveness");
37020b57cec5SDimitry Andric DAG = static_cast<ScheduleDAGMILive*>(dag);
37030b57cec5SDimitry Andric DAG->computeDFSResult();
37040b57cec5SDimitry Andric Cmp.DFSResult = DAG->getDFSResult();
37050b57cec5SDimitry Andric Cmp.ScheduledTrees = &DAG->getScheduledTrees();
37060b57cec5SDimitry Andric ReadyQ.clear();
37070b57cec5SDimitry Andric }
37080b57cec5SDimitry Andric
registerRoots()37090b57cec5SDimitry Andric void registerRoots() override {
37100b57cec5SDimitry Andric // Restore the heap in ReadyQ with the updated DFS results.
37110b57cec5SDimitry Andric std::make_heap(ReadyQ.begin(), ReadyQ.end(), Cmp);
37120b57cec5SDimitry Andric }
37130b57cec5SDimitry Andric
37140b57cec5SDimitry Andric /// Implement MachineSchedStrategy interface.
37150b57cec5SDimitry Andric /// -----------------------------------------
37160b57cec5SDimitry Andric
37170b57cec5SDimitry Andric /// Callback to select the highest priority node from the ready Q.
pickNode(bool & IsTopNode)37180b57cec5SDimitry Andric SUnit *pickNode(bool &IsTopNode) override {
37190b57cec5SDimitry Andric if (ReadyQ.empty()) return nullptr;
37200b57cec5SDimitry Andric std::pop_heap(ReadyQ.begin(), ReadyQ.end(), Cmp);
37210b57cec5SDimitry Andric SUnit *SU = ReadyQ.back();
37220b57cec5SDimitry Andric ReadyQ.pop_back();
37230b57cec5SDimitry Andric IsTopNode = false;
37240b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Pick node "
37250b57cec5SDimitry Andric << "SU(" << SU->NodeNum << ") "
37260b57cec5SDimitry Andric << " ILP: " << DAG->getDFSResult()->getILP(SU)
37270b57cec5SDimitry Andric << " Tree: " << DAG->getDFSResult()->getSubtreeID(SU)
37280b57cec5SDimitry Andric << " @"
37290b57cec5SDimitry Andric << DAG->getDFSResult()->getSubtreeLevel(
37300b57cec5SDimitry Andric DAG->getDFSResult()->getSubtreeID(SU))
37310b57cec5SDimitry Andric << '\n'
37320b57cec5SDimitry Andric << "Scheduling " << *SU->getInstr());
37330b57cec5SDimitry Andric return SU;
37340b57cec5SDimitry Andric }
37350b57cec5SDimitry Andric
37360b57cec5SDimitry Andric /// Scheduler callback to notify that a new subtree is scheduled.
scheduleTree(unsigned SubtreeID)37370b57cec5SDimitry Andric void scheduleTree(unsigned SubtreeID) override {
37380b57cec5SDimitry Andric std::make_heap(ReadyQ.begin(), ReadyQ.end(), Cmp);
37390b57cec5SDimitry Andric }
37400b57cec5SDimitry Andric
37410b57cec5SDimitry Andric /// Callback after a node is scheduled. Mark a newly scheduled tree, notify
37420b57cec5SDimitry Andric /// DFSResults, and resort the priority Q.
schedNode(SUnit * SU,bool IsTopNode)37430b57cec5SDimitry Andric void schedNode(SUnit *SU, bool IsTopNode) override {
37440b57cec5SDimitry Andric assert(!IsTopNode && "SchedDFSResult needs bottom-up");
37450b57cec5SDimitry Andric }
37460b57cec5SDimitry Andric
releaseTopNode(SUnit *)37470b57cec5SDimitry Andric void releaseTopNode(SUnit *) override { /*only called for top roots*/ }
37480b57cec5SDimitry Andric
releaseBottomNode(SUnit * SU)37490b57cec5SDimitry Andric void releaseBottomNode(SUnit *SU) override {
37500b57cec5SDimitry Andric ReadyQ.push_back(SU);
37510b57cec5SDimitry Andric std::push_heap(ReadyQ.begin(), ReadyQ.end(), Cmp);
37520b57cec5SDimitry Andric }
37530b57cec5SDimitry Andric };
37540b57cec5SDimitry Andric
37550b57cec5SDimitry Andric } // end anonymous namespace
37560b57cec5SDimitry Andric
createILPMaxScheduler(MachineSchedContext * C)37570b57cec5SDimitry Andric static ScheduleDAGInstrs *createILPMaxScheduler(MachineSchedContext *C) {
37588bcb0991SDimitry Andric return new ScheduleDAGMILive(C, std::make_unique<ILPScheduler>(true));
37590b57cec5SDimitry Andric }
createILPMinScheduler(MachineSchedContext * C)37600b57cec5SDimitry Andric static ScheduleDAGInstrs *createILPMinScheduler(MachineSchedContext *C) {
37618bcb0991SDimitry Andric return new ScheduleDAGMILive(C, std::make_unique<ILPScheduler>(false));
37620b57cec5SDimitry Andric }
37630b57cec5SDimitry Andric
37640b57cec5SDimitry Andric static MachineSchedRegistry ILPMaxRegistry(
37650b57cec5SDimitry Andric "ilpmax", "Schedule bottom-up for max ILP", createILPMaxScheduler);
37660b57cec5SDimitry Andric static MachineSchedRegistry ILPMinRegistry(
37670b57cec5SDimitry Andric "ilpmin", "Schedule bottom-up for min ILP", createILPMinScheduler);
37680b57cec5SDimitry Andric
37690b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
37700b57cec5SDimitry Andric // Machine Instruction Shuffler for Correctness Testing
37710b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
37720b57cec5SDimitry Andric
37730b57cec5SDimitry Andric #ifndef NDEBUG
37740b57cec5SDimitry Andric namespace {
37750b57cec5SDimitry Andric
37760b57cec5SDimitry Andric /// Apply a less-than relation on the node order, which corresponds to the
37770b57cec5SDimitry Andric /// instruction order prior to scheduling. IsReverse implements greater-than.
37780b57cec5SDimitry Andric template<bool IsReverse>
37790b57cec5SDimitry Andric struct SUnitOrder {
operator ()__anonde6daefc0611::SUnitOrder37800b57cec5SDimitry Andric bool operator()(SUnit *A, SUnit *B) const {
37810b57cec5SDimitry Andric if (IsReverse)
37820b57cec5SDimitry Andric return A->NodeNum > B->NodeNum;
37830b57cec5SDimitry Andric else
37840b57cec5SDimitry Andric return A->NodeNum < B->NodeNum;
37850b57cec5SDimitry Andric }
37860b57cec5SDimitry Andric };
37870b57cec5SDimitry Andric
37880b57cec5SDimitry Andric /// Reorder instructions as much as possible.
37890b57cec5SDimitry Andric class InstructionShuffler : public MachineSchedStrategy {
37900b57cec5SDimitry Andric bool IsAlternating;
37910b57cec5SDimitry Andric bool IsTopDown;
37920b57cec5SDimitry Andric
37930b57cec5SDimitry Andric // Using a less-than relation (SUnitOrder<false>) for the TopQ priority
37940b57cec5SDimitry Andric // gives nodes with a higher number higher priority causing the latest
37950b57cec5SDimitry Andric // instructions to be scheduled first.
37960b57cec5SDimitry Andric PriorityQueue<SUnit*, std::vector<SUnit*>, SUnitOrder<false>>
37970b57cec5SDimitry Andric TopQ;
37980b57cec5SDimitry Andric
37990b57cec5SDimitry Andric // When scheduling bottom-up, use greater-than as the queue priority.
38000b57cec5SDimitry Andric PriorityQueue<SUnit*, std::vector<SUnit*>, SUnitOrder<true>>
38010b57cec5SDimitry Andric BottomQ;
38020b57cec5SDimitry Andric
38030b57cec5SDimitry Andric public:
InstructionShuffler(bool alternate,bool topdown)38040b57cec5SDimitry Andric InstructionShuffler(bool alternate, bool topdown)
38050b57cec5SDimitry Andric : IsAlternating(alternate), IsTopDown(topdown) {}
38060b57cec5SDimitry Andric
initialize(ScheduleDAGMI *)38070b57cec5SDimitry Andric void initialize(ScheduleDAGMI*) override {
38080b57cec5SDimitry Andric TopQ.clear();
38090b57cec5SDimitry Andric BottomQ.clear();
38100b57cec5SDimitry Andric }
38110b57cec5SDimitry Andric
38120b57cec5SDimitry Andric /// Implement MachineSchedStrategy interface.
38130b57cec5SDimitry Andric /// -----------------------------------------
38140b57cec5SDimitry Andric
pickNode(bool & IsTopNode)38150b57cec5SDimitry Andric SUnit *pickNode(bool &IsTopNode) override {
38160b57cec5SDimitry Andric SUnit *SU;
38170b57cec5SDimitry Andric if (IsTopDown) {
38180b57cec5SDimitry Andric do {
38190b57cec5SDimitry Andric if (TopQ.empty()) return nullptr;
38200b57cec5SDimitry Andric SU = TopQ.top();
38210b57cec5SDimitry Andric TopQ.pop();
38220b57cec5SDimitry Andric } while (SU->isScheduled);
38230b57cec5SDimitry Andric IsTopNode = true;
38240b57cec5SDimitry Andric } else {
38250b57cec5SDimitry Andric do {
38260b57cec5SDimitry Andric if (BottomQ.empty()) return nullptr;
38270b57cec5SDimitry Andric SU = BottomQ.top();
38280b57cec5SDimitry Andric BottomQ.pop();
38290b57cec5SDimitry Andric } while (SU->isScheduled);
38300b57cec5SDimitry Andric IsTopNode = false;
38310b57cec5SDimitry Andric }
38320b57cec5SDimitry Andric if (IsAlternating)
38330b57cec5SDimitry Andric IsTopDown = !IsTopDown;
38340b57cec5SDimitry Andric return SU;
38350b57cec5SDimitry Andric }
38360b57cec5SDimitry Andric
schedNode(SUnit * SU,bool IsTopNode)38370b57cec5SDimitry Andric void schedNode(SUnit *SU, bool IsTopNode) override {}
38380b57cec5SDimitry Andric
releaseTopNode(SUnit * SU)38390b57cec5SDimitry Andric void releaseTopNode(SUnit *SU) override {
38400b57cec5SDimitry Andric TopQ.push(SU);
38410b57cec5SDimitry Andric }
releaseBottomNode(SUnit * SU)38420b57cec5SDimitry Andric void releaseBottomNode(SUnit *SU) override {
38430b57cec5SDimitry Andric BottomQ.push(SU);
38440b57cec5SDimitry Andric }
38450b57cec5SDimitry Andric };
38460b57cec5SDimitry Andric
38470b57cec5SDimitry Andric } // end anonymous namespace
38480b57cec5SDimitry Andric
createInstructionShuffler(MachineSchedContext * C)38490b57cec5SDimitry Andric static ScheduleDAGInstrs *createInstructionShuffler(MachineSchedContext *C) {
38500b57cec5SDimitry Andric bool Alternate = !ForceTopDown && !ForceBottomUp;
38510b57cec5SDimitry Andric bool TopDown = !ForceBottomUp;
38520b57cec5SDimitry Andric assert((TopDown || !ForceTopDown) &&
38530b57cec5SDimitry Andric "-misched-topdown incompatible with -misched-bottomup");
38540b57cec5SDimitry Andric return new ScheduleDAGMILive(
38558bcb0991SDimitry Andric C, std::make_unique<InstructionShuffler>(Alternate, TopDown));
38560b57cec5SDimitry Andric }
38570b57cec5SDimitry Andric
38580b57cec5SDimitry Andric static MachineSchedRegistry ShufflerRegistry(
38590b57cec5SDimitry Andric "shuffle", "Shuffle machine instructions alternating directions",
38600b57cec5SDimitry Andric createInstructionShuffler);
38610b57cec5SDimitry Andric #endif // !NDEBUG
38620b57cec5SDimitry Andric
38630b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
38640b57cec5SDimitry Andric // GraphWriter support for ScheduleDAGMILive.
38650b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
38660b57cec5SDimitry Andric
38670b57cec5SDimitry Andric #ifndef NDEBUG
38680b57cec5SDimitry Andric namespace llvm {
38690b57cec5SDimitry Andric
38700b57cec5SDimitry Andric template<> struct GraphTraits<
38710b57cec5SDimitry Andric ScheduleDAGMI*> : public GraphTraits<ScheduleDAG*> {};
38720b57cec5SDimitry Andric
38730b57cec5SDimitry Andric template<>
38740b57cec5SDimitry Andric struct DOTGraphTraits<ScheduleDAGMI*> : public DefaultDOTGraphTraits {
DOTGraphTraitsllvm::DOTGraphTraits38750b57cec5SDimitry Andric DOTGraphTraits(bool isSimple = false) : DefaultDOTGraphTraits(isSimple) {}
38760b57cec5SDimitry Andric
getGraphNamellvm::DOTGraphTraits38770b57cec5SDimitry Andric static std::string getGraphName(const ScheduleDAG *G) {
38785ffd83dbSDimitry Andric return std::string(G->MF.getName());
38790b57cec5SDimitry Andric }
38800b57cec5SDimitry Andric
renderGraphFromBottomUpllvm::DOTGraphTraits38810b57cec5SDimitry Andric static bool renderGraphFromBottomUp() {
38820b57cec5SDimitry Andric return true;
38830b57cec5SDimitry Andric }
38840b57cec5SDimitry Andric
isNodeHiddenllvm::DOTGraphTraits3885af732203SDimitry Andric static bool isNodeHidden(const SUnit *Node, const ScheduleDAG *G) {
38860b57cec5SDimitry Andric if (ViewMISchedCutoff == 0)
38870b57cec5SDimitry Andric return false;
38880b57cec5SDimitry Andric return (Node->Preds.size() > ViewMISchedCutoff
38890b57cec5SDimitry Andric || Node->Succs.size() > ViewMISchedCutoff);
38900b57cec5SDimitry Andric }
38910b57cec5SDimitry Andric
38920b57cec5SDimitry Andric /// If you want to override the dot attributes printed for a particular
38930b57cec5SDimitry Andric /// edge, override this method.
getEdgeAttributesllvm::DOTGraphTraits38940b57cec5SDimitry Andric static std::string getEdgeAttributes(const SUnit *Node,
38950b57cec5SDimitry Andric SUnitIterator EI,
38960b57cec5SDimitry Andric const ScheduleDAG *Graph) {
38970b57cec5SDimitry Andric if (EI.isArtificialDep())
38980b57cec5SDimitry Andric return "color=cyan,style=dashed";
38990b57cec5SDimitry Andric if (EI.isCtrlDep())
39000b57cec5SDimitry Andric return "color=blue,style=dashed";
39010b57cec5SDimitry Andric return "";
39020b57cec5SDimitry Andric }
39030b57cec5SDimitry Andric
getNodeLabelllvm::DOTGraphTraits39040b57cec5SDimitry Andric static std::string getNodeLabel(const SUnit *SU, const ScheduleDAG *G) {
39050b57cec5SDimitry Andric std::string Str;
39060b57cec5SDimitry Andric raw_string_ostream SS(Str);
39070b57cec5SDimitry Andric const ScheduleDAGMI *DAG = static_cast<const ScheduleDAGMI*>(G);
39080b57cec5SDimitry Andric const SchedDFSResult *DFS = DAG->hasVRegLiveness() ?
39090b57cec5SDimitry Andric static_cast<const ScheduleDAGMILive*>(G)->getDFSResult() : nullptr;
39100b57cec5SDimitry Andric SS << "SU:" << SU->NodeNum;
39110b57cec5SDimitry Andric if (DFS)
39120b57cec5SDimitry Andric SS << " I:" << DFS->getNumInstrs(SU);
39130b57cec5SDimitry Andric return SS.str();
39140b57cec5SDimitry Andric }
39150b57cec5SDimitry Andric
getNodeDescriptionllvm::DOTGraphTraits39160b57cec5SDimitry Andric static std::string getNodeDescription(const SUnit *SU, const ScheduleDAG *G) {
39170b57cec5SDimitry Andric return G->getGraphNodeLabel(SU);
39180b57cec5SDimitry Andric }
39190b57cec5SDimitry Andric
getNodeAttributesllvm::DOTGraphTraits39200b57cec5SDimitry Andric static std::string getNodeAttributes(const SUnit *N, const ScheduleDAG *G) {
39210b57cec5SDimitry Andric std::string Str("shape=Mrecord");
39220b57cec5SDimitry Andric const ScheduleDAGMI *DAG = static_cast<const ScheduleDAGMI*>(G);
39230b57cec5SDimitry Andric const SchedDFSResult *DFS = DAG->hasVRegLiveness() ?
39240b57cec5SDimitry Andric static_cast<const ScheduleDAGMILive*>(G)->getDFSResult() : nullptr;
39250b57cec5SDimitry Andric if (DFS) {
39260b57cec5SDimitry Andric Str += ",style=filled,fillcolor=\"#";
39270b57cec5SDimitry Andric Str += DOT::getColorString(DFS->getSubtreeID(N));
39280b57cec5SDimitry Andric Str += '"';
39290b57cec5SDimitry Andric }
39300b57cec5SDimitry Andric return Str;
39310b57cec5SDimitry Andric }
39320b57cec5SDimitry Andric };
39330b57cec5SDimitry Andric
39340b57cec5SDimitry Andric } // end namespace llvm
39350b57cec5SDimitry Andric #endif // NDEBUG
39360b57cec5SDimitry Andric
39370b57cec5SDimitry Andric /// viewGraph - Pop up a ghostview window with the reachable parts of the DAG
39380b57cec5SDimitry Andric /// rendered using 'dot'.
viewGraph(const Twine & Name,const Twine & Title)39390b57cec5SDimitry Andric void ScheduleDAGMI::viewGraph(const Twine &Name, const Twine &Title) {
39400b57cec5SDimitry Andric #ifndef NDEBUG
39410b57cec5SDimitry Andric ViewGraph(this, Name, false, Title);
39420b57cec5SDimitry Andric #else
39430b57cec5SDimitry Andric errs() << "ScheduleDAGMI::viewGraph is only available in debug builds on "
39440b57cec5SDimitry Andric << "systems with Graphviz or gv!\n";
39450b57cec5SDimitry Andric #endif // NDEBUG
39460b57cec5SDimitry Andric }
39470b57cec5SDimitry Andric
39480b57cec5SDimitry Andric /// Out-of-line implementation with no arguments is handy for gdb.
viewGraph()39490b57cec5SDimitry Andric void ScheduleDAGMI::viewGraph() {
39500b57cec5SDimitry Andric viewGraph(getDAGName(), "Scheduling-Units Graph for " + getDAGName());
39510b57cec5SDimitry Andric }
3952