LLVM: lib/CodeGen/PostRASchedulerList.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
36#include "llvm/Config/llvm-config.h"
44using namespace llvm;
45
46#define DEBUG_TYPE "post-RA-sched"
47
48STATISTIC(NumNoops, "Number of noops inserted");
49STATISTIC(NumStalls, "Number of pipeline stalls");
50STATISTIC(NumFixedAnti, "Number of fixed anti-dependencies");
51
52
53
54
57 cl::desc("Enable scheduling after register allocation"),
61 cl::desc("Break post-RA scheduling anti-dependencies: "
62 "\"critical\", \"all\", or \"none\""),
64
65
68 cl::desc("Debug control MBBs that are scheduled"),
72 cl::desc("Debug control MBBs that are scheduled"),
74
76
77namespace {
78class PostRAScheduler {
84
85public:
88 : TII(MF.getSubtarget().getInstrInfo()), MLI(MLI), AA(AA), TM(TM) {}
89 bool run(MachineFunction &MF);
90};
91
93public:
94 static char ID;
95 PostRASchedulerLegacy() : MachineFunctionPass(ID) {}
96
97 void getAnalysisUsage(AnalysisUsage &AU) const override {
101 AU.addRequired();
102 AU.addPreserved();
103 AU.addRequired();
104 AU.addPreserved();
106 }
107
108 MachineFunctionProperties getRequiredProperties() const override {
109 return MachineFunctionProperties().setNoVRegs();
110 }
111
112 bool runOnMachineFunction(MachineFunction &Fn) override;
113};
114char PostRASchedulerLegacy::ID = 0;
115
117
118
119 LatencyPriorityQueue AvailableQueue;
120
121
122
123
124
125 std::vector<SUnit *> PendingQueue;
126
127
128 ScheduleHazardRecognizer *HazardRec;
129
130
131 AntiDepBreaker *AntiDepBreak;
132
133
135
136
137 std::vector<SUnit *> Sequence;
138
139
140 std::vector<std::unique_ptr> Mutations;
141
142
143
144
145
146 unsigned EndIndex = 0;
147
148public:
149 SchedulePostRATDList(
150 MachineFunction &MF, MachineLoopInfo &MLI, AliasAnalysis *AA,
151 const RegisterClassInfo &,
153 SmallVectorImpl<const TargetRegisterClass *> &CriticalPathRCs);
154
155 ~SchedulePostRATDList() override;
156
157
158
159
160 void startBlock(MachineBasicBlock *BB) override;
161
162
163 void setEndIndex(unsigned EndIdx) { EndIndex = EndIdx; }
164
165
168 unsigned regioninstrs) override;
169
170
171 void exitRegion() override;
172
173
174
175 void schedule() override;
176
177 void EmitSchedule();
178
179
180
181
182 void Observe(MachineInstr &MI, unsigned Count);
183
184
185
186 void finishBlock() override;
187
188private:
189
190 void postProcessDAG();
191
192 void ReleaseSucc(SUnit *SU, SDep *SuccEdge);
193 void ReleaseSuccessors(SUnit *SU);
194 void ScheduleNodeTopDown(SUnit *SU, unsigned CurCycle);
195 void ListScheduleTopDown();
196
197 void dumpSchedule() const;
198 void emitNoop(unsigned CurCycle);
199};
200}
201
203
205 "Post RA top-down list latency scheduler", false, false)
206
207SchedulePostRATDList::SchedulePostRATDList(
213
215 MF.getSubtarget().getInstrItineraryData();
216 HazardRec =
217 MF.getSubtarget().getInstrInfo()->CreateTargetPostRAHazardRecognizer(
218 InstrItins, this);
219 MF.getSubtarget().getPostRAMutations(Mutations);
220
221 assert((AntiDepMode == TargetSubtargetInfo::ANTIDEP_NONE ||
222 MRI.tracksLiveness()) &&
223 "Live-ins must be accurate for anti-dependency breaking");
224 AntiDepBreak = ((AntiDepMode == TargetSubtargetInfo::ANTIDEP_ALL)
226 : ((AntiDepMode == TargetSubtargetInfo::ANTIDEP_CRITICAL)
228 : nullptr));
229}
230
231SchedulePostRATDList::~SchedulePostRATDList() {
232 delete HazardRec;
233 delete AntiDepBreak;
234}
235
236
237void SchedulePostRATDList::enterRegion(MachineBasicBlock *bb,
240 unsigned regioninstrs) {
242 Sequence.clear();
243}
244
245
246void SchedulePostRATDList::exitRegion() {
248 dbgs() << "*** Final schedule ***\n";
249 dumpSchedule();
250 dbgs() << '\n';
251 });
253}
254
255#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
256
257LLVM_DUMP_METHOD void SchedulePostRATDList::dumpSchedule() const {
258 for (const SUnit *SU : Sequence) {
259 if (SU)
260 dumpNode(*SU);
261 else
262 dbgs() << "**** NOOP ****\n";
263 }
264}
265#endif
266
269
272
273 return ST.enablePostRAScheduler() &&
274 OptLevel >= ST.getOptLevelToEnablePostRAScheduler();
275}
276
277bool PostRAScheduler::run(MachineFunction &MF) {
279
281 return false;
282
287 ? TargetSubtargetInfo::ANTIDEP_ALL
289 ? TargetSubtargetInfo::ANTIDEP_CRITICAL
290 : TargetSubtargetInfo::ANTIDEP_NONE);
291 }
293 Subtarget.getCriticalPathRCs(CriticalPathRCs);
295
297
298 SchedulePostRATDList Scheduler(MF, *MLI, AA, RegClassInfo, AntiDepMode,
299 CriticalPathRCs);
300
301
302 for (auto &MBB : MF) {
303#ifndef NDEBUG
304
306 static int bbcnt = 0;
308 continue;
309 dbgs() << "*** DEBUG scheduling " << MF.getName() << ":"
311 }
312#endif
313
314
316
317
318
322 MachineInstr &MI = *std::prev(I);
324
325
326
329 Scheduler.setEndIndex(CurrentCount);
333 Current = &MI;
334 CurrentCount = Count;
336 }
338 if (MI.isBundle())
339 Count -= MI.getBundleSize();
340 }
341 assert(Count == 0 && "Instruction count mismatch!");
342 assert((MBB.begin() == Current || CurrentCount != 0) &&
343 "Instruction count mismatch!");
345 Scheduler.setEndIndex(CurrentCount);
349
350
352
353
355 }
356
357 return true;
358}
359
360bool PostRASchedulerLegacy::runOnMachineFunction(MachineFunction &MF) {
362 return false;
363
364 MachineLoopInfo *MLI = &getAnalysis().getLI();
365 AliasAnalysis *AA = &getAnalysis().getAAResults();
366 const TargetMachine *TM =
367 &getAnalysis().getTM();
368 PostRAScheduler Impl(MF, MLI, AA, TM);
369 return Impl.run(MF);
370}
371
372PreservedAnalyses
376
379 .getManager();
381 PostRAScheduler Impl(MF, MLI, AA, TM);
382 bool Changed = Impl.run(MF);
385
390 return PA;
391}
392
393
394
395
397
399
400
401 HazardRec->Reset();
402 if (AntiDepBreak)
404}
405
406
407
408void SchedulePostRATDList::schedule() {
409
410 buildSchedGraph(AA);
411
412 if (AntiDepBreak) {
413 unsigned Broken =
415 EndIndex, DbgValues);
416
417 if (Broken != 0) {
418
419
420
421
422
423
425 buildSchedGraph(AA);
426
427 NumFixedAnti += Broken;
428 }
429 }
430
431 postProcessDAG();
432
433 LLVM_DEBUG(dbgs() << "********** List Scheduling **********\n");
435
436 AvailableQueue.initNodes(SUnits);
437 ListScheduleTopDown();
439}
440
441
442
443
444void SchedulePostRATDList::Observe(MachineInstr &MI, unsigned Count) {
445 if (AntiDepBreak)
447}
448
449
450
451void SchedulePostRATDList::finishBlock() {
452 if (AntiDepBreak)
454
455
457}
458
459
460void SchedulePostRATDList::postProcessDAG() {
461 for (auto &M : Mutations)
462 M->apply(this);
463}
464
465
466
467
468
469
470
471void SchedulePostRATDList::ReleaseSucc(SUnit *SU, SDep *SuccEdge) {
472 SUnit *SuccSU = SuccEdge->getSUnit();
473
474 if (SuccEdge->isWeak()) {
476 return;
477 }
478#ifndef NDEBUG
480 dbgs() << "*** Scheduling failed! ***\n";
481 dumpNode(*SuccSU);
482 dbgs() << " has been released too many times!\n";
484 }
485#endif
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501 if (SuccSU->NumPredsLeft == 0 && SuccSU != &ExitSU)
502 PendingQueue.push_back(SuccSU);
503}
504
505
506void SchedulePostRATDList::ReleaseSuccessors(SUnit *SU) {
509 ReleaseSucc(SU, &*I);
510 }
511}
512
513
514
515
516void SchedulePostRATDList::ScheduleNodeTopDown(SUnit *SU, unsigned CurCycle) {
517 LLVM_DEBUG(dbgs() << "*** Scheduling [" << CurCycle << "]: ");
519
522 "Node scheduled above its depth!");
524
525 ReleaseSuccessors(SU);
528}
529
530
531void SchedulePostRATDList::emitNoop(unsigned CurCycle) {
532 LLVM_DEBUG(dbgs() << "*** Emitting noop in cycle " << CurCycle << '\n');
534 Sequence.push_back(nullptr);
535 ++NumNoops;
536}
537
538
539
540void SchedulePostRATDList::ListScheduleTopDown() {
541 unsigned CurCycle = 0;
542
543
544
545
546
547 HazardRec->Reset();
548
549
550 ReleaseSuccessors(&EntrySU);
551
552
553 for (SUnit &SUnit : SUnits) {
554
555 if (!SUnit.NumPredsLeft && !SUnit.isAvailable) {
556 AvailableQueue.push(&SUnit);
557 SUnit.isAvailable = true;
558 }
559 }
560
561
562
563 bool CycleHasInsts = false;
564
565
566
567 std::vector<SUnit*> NotReady;
568 Sequence.reserve(SUnits.size());
569 while (!AvailableQueue.empty() || !PendingQueue.empty()) {
570
571
572 unsigned MinDepth = ~0u;
573 for (unsigned i = 0, e = PendingQueue.size(); i != e; ++i) {
574 if (PendingQueue[i]->getDepth() <= CurCycle) {
575 AvailableQueue.push(PendingQueue[i]);
576 PendingQueue[i]->isAvailable = true;
577 PendingQueue[i] = PendingQueue.back();
578 PendingQueue.pop_back();
579 --i; --e;
580 } else if (PendingQueue[i]->getDepth() < MinDepth)
581 MinDepth = PendingQueue[i]->getDepth();
582 }
583
585 AvailableQueue.dump(this));
586
587 SUnit *FoundSUnit = nullptr, *NotPreferredSUnit = nullptr;
588 bool HasNoopHazards = false;
589 while (!AvailableQueue.empty()) {
590 SUnit *CurSUnit = AvailableQueue.pop();
591
593 HazardRec->getHazardType(CurSUnit, 0);
596 if (!NotPreferredSUnit) {
597
598
599
600
601 NotPreferredSUnit = CurSUnit;
602 continue;
603 }
604 } else {
605 FoundSUnit = CurSUnit;
606 break;
607 }
608 }
609
610
612
613 NotReady.push_back(CurSUnit);
614 }
615
616
617
618
619 if (NotPreferredSUnit) {
620 if (!FoundSUnit) {
622 dbgs() << "*** Will schedule a non-preferred instruction...\n");
623 FoundSUnit = NotPreferredSUnit;
624 } else {
625 AvailableQueue.push(NotPreferredSUnit);
626 }
627
628 NotPreferredSUnit = nullptr;
629 }
630
631
632 if (!NotReady.empty()) {
633 AvailableQueue.push_all(NotReady);
634 NotReady.clear();
635 }
636
637
638 if (FoundSUnit) {
639
640 unsigned NumPreNoops = HazardRec->PreEmitNoops(FoundSUnit);
641 for (unsigned i = 0; i != NumPreNoops; ++i)
642 emitNoop(CurCycle);
643
644
645 ScheduleNodeTopDown(FoundSUnit, CurCycle);
647 CycleHasInsts = true;
649 LLVM_DEBUG(dbgs() << "*** Max instructions per cycle " << CurCycle
650 << '\n');
652 ++CurCycle;
653 CycleHasInsts = false;
654 }
655 } else {
656 if (CycleHasInsts) {
657 LLVM_DEBUG(dbgs() << "*** Finished cycle " << CurCycle << '\n');
659 } else if (!HasNoopHazards) {
660
661
662 LLVM_DEBUG(dbgs() << "*** Stall in cycle " << CurCycle << '\n');
664 ++NumStalls;
665 } else {
666
667
668
669 emitNoop(CurCycle);
670 }
671
672 ++CurCycle;
673 CycleHasInsts = false;
674 }
675 }
676
677#ifndef NDEBUG
678 unsigned ScheduledNodes = VerifyScheduledDAG(false);
679 unsigned Noops = llvm::count(Sequence, nullptr);
681 "The number of nodes scheduled doesn't match the expected number!");
682#endif
683}
684
685
686void SchedulePostRATDList::EmitSchedule() {
687 RegionBegin = RegionEnd;
688
689
690 if (FirstDbgValue)
691 BB->splice(RegionEnd, BB, FirstDbgValue);
692
693
694 for (unsigned i = 0, e = Sequence.size(); i != e; i++) {
695 if (SUnit *SU = Sequence[i])
697 else
698
700
701
702
703 if (i == 0)
704 RegionBegin = std::prev(RegionEnd);
705 }
706
707
708 for (std::vector<std::pair<MachineInstr *, MachineInstr *> >::iterator
709 DI = DbgValues.end(), DE = DbgValues.begin(); DI != DE; --DI) {
710 std::pair<MachineInstr *, MachineInstr *> P = *std::prev(DI);
711 MachineInstr *DbgValue = P.first;
713 BB->splice(++OrigPrivMI, BB, DbgValue);
714 }
715 DbgValues.clear();
716 FirstDbgValue = nullptr;
717}
unsigned const MachineRegisterInfo * MRI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static cl::opt< int > DebugDiv("agg-antidep-debugdiv", cl::desc("Debug control for aggressive anti-dep breaker"), cl::init(0), cl::Hidden)
static cl::opt< int > DebugMod("agg-antidep-debugmod", cl::desc("Debug control for aggressive anti-dep breaker"), cl::init(0), cl::Hidden)
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
#define LLVM_DUMP_METHOD
Mark debug helper function definitions like dump() that should not be stripped from debug builds.
const HexagonInstrInfo * TII
Machine Instruction Scheduler
FunctionAnalysisManager FAM
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
static cl::opt< int > DebugDiv("postra-sched-debugdiv", cl::desc("Debug control MBBs that are scheduled"), cl::init(0), cl::Hidden)
static cl::opt< bool > EnablePostRAScheduler("post-RA-scheduler", cl::desc("Enable scheduling after register allocation"), cl::init(false), cl::Hidden)
static cl::opt< std::string > EnableAntiDepBreaking("break-anti-dependencies", cl::desc("Break post-RA scheduling anti-dependencies: " "\"critical\", \"all\", or \"none\""), cl::init("none"), cl::Hidden)
static bool enablePostRAScheduler(const TargetSubtargetInfo &ST, CodeGenOptLevel OptLevel)
Definition PostRASchedulerList.cpp:267
static cl::opt< int > DebugMod("postra-sched-debugmod", cl::desc("Debug control MBBs that are scheduled"), cl::init(0), cl::Hidden)
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
Target-Independent Code Generator Pass Configuration Options pass.
A manager for alias analyses.
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
AnalysisUsage & addRequired()
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
LLVM_ABI void setPreservesCFG()
This function should be called by the pass, iff they do not:
virtual void FinishBlock()=0
Finish anti-dep breaking for a basic block.
virtual unsigned BreakAntiDependencies(const std::vector< SUnit > &SUnits, MachineBasicBlock::iterator Begin, MachineBasicBlock::iterator End, unsigned InsertPosIndex, DbgValueVector &DbgValues)=0
Identifiy anti-dependencies within a basic-block region and break them by renaming registers.
virtual void Observe(MachineInstr &MI, unsigned Count, unsigned InsertPosIndex)=0
Update liveness information to account for the current instruction, which will not be scheduled.
virtual ~AntiDepBreaker()
virtual void StartBlock(MachineBasicBlock *BB)=0
Initialize anti-dep breaking for a new basic block.
Represents analyses that only rely on functions' control flow.
void insertNoop(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI) const override
Insert a noop into the instruction stream at the specified point.
bool isSchedulingBoundary(const MachineInstr &MI, const MachineBasicBlock *MBB, const MachineFunction &MF) const override
Test if the given instruction should be considered a scheduling boundary.
Itinerary data supplied by a subtarget to be used by a target.
void releaseState() override
void push(SUnit *U) override
LLVM_DUMP_METHOD void dump(ScheduleDAG *DAG) const override
void scheduledNode(SUnit *SU) override
As each node is scheduled, this method is invoked.
void initNodes(std::vector< SUnit > &sunits) override
bool empty() const override
An RAII based helper class to modify MachineFunctionProperties when running pass.
void splice(iterator Where, MachineBasicBlock *Other, iterator From)
Take an instruction from MBB 'Other' at the position From, and insert it into this MBB right before '...
MachineInstrBundleIterator< MachineInstr > iterator
Analysis pass which computes a MachineDominatorTree.
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
Function & getFunction()
Return the LLVM function that this machine code represents.
Analysis pass that exposes the MachineLoopInfo for a machine function.
PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
Definition PostRASchedulerList.cpp:373
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
PreservedAnalyses & preserveSet()
Mark an analysis set as preserved.
PreservedAnalyses & preserve()
Mark an analysis as preserved.
LLVM_ABI void runOnMachineFunction(const MachineFunction &MF, bool Rev=false)
runOnFunction - Prepare to answer questions about MF.
bool isWeak() const
Tests if this a weak dependence.
unsigned getDepth() const
Returns the depth of this node, which is the length of the maximum path up to any node which has no p...
bool isScheduled
True once scheduled.
SmallVector< SDep, 4 > Succs
All sunit successors.
SmallVectorImpl< SDep >::iterator succ_iterator
LLVM_ABI void setDepthToAtLeast(unsigned NewDepth)
If NewDepth is greater than this node's depth value, sets it to be the new depth value.
MachineInstr * getInstr() const
Returns the representative MachineInstr for this SUnit.
A ScheduleDAG for scheduling lists of MachineInstr.
virtual void finishBlock()
Cleans up after scheduling in the given block.
virtual void startBlock(MachineBasicBlock *BB)
Prepares to perform scheduling in the given block.
virtual void exitRegion()
Called when the scheduler has finished scheduling the current region.
virtual void enterRegion(MachineBasicBlock *bb, MachineBasicBlock::iterator begin, MachineBasicBlock::iterator end, unsigned regioninstrs)
Initialize the DAG and common scheduler state for a new scheduling region.
void clearDAG()
Clears the DAG state (between regions).
virtual void Reset()
Reset - This callback is invoked when a new block of instructions is about to be schedule.
virtual void EmitInstruction(SUnit *)
EmitInstruction - This callback is invoked when an instruction is emitted, to advance the hazard stat...
virtual bool atIssueLimit() const
atIssueLimit - Return true if no more instructions may be issued in this cycle.
virtual bool ShouldPreferAnother(SUnit *)
ShouldPreferAnother - This callback may be invoked if getHazardType returns NoHazard.
virtual void EmitNoop()
EmitNoop - This callback is invoked when a noop was added to the instruction stream.
virtual void AdvanceCycle()
AdvanceCycle - This callback is invoked whenever the next top-down instruction to be scheduled cannot...
virtual HazardType getHazardType(SUnit *, int Stalls=0)
getHazardType - Return the hazard type of emitting this node.
virtual unsigned PreEmitNoops(SUnit *)
PreEmitNoops - This callback is invoked prior to emitting an instruction.
void push_all(const std::vector< SUnit * > &Nodes)
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
TargetInstrInfo - Interface to description of machine instruction set.
Primary interface to the complete machine description for the target machine.
CodeGenOptLevel getOptLevel() const
Returns the optimization level: None, Less, Default, or Aggressive.
TargetSubtargetInfo - Generic base class for all target subtargets.
enum { ANTIDEP_NONE, ANTIDEP_CRITICAL, ANTIDEP_ALL } AntiDepBreakMode
virtual AntiDepBreakMode getAntiDepBreakMode() const
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Abstract Attribute helper functions.
initializer< Ty > init(const Ty &Val)
PointerTypeMap run(const Module &M)
Compute the PointerTypeMap for the module M.
Sequence
A sequence of states that a pointer may go through in which an objc_retain and objc_release are actua...
This is an optimization pass for GlobalISel generic memory operations.
void dump(const SparseBitVector< ElementSize > &LHS, raw_ostream &out)
AntiDepBreaker * createAggressiveAntiDepBreaker(MachineFunction &MFi, const RegisterClassInfo &RCI, TargetSubtargetInfo::RegClassVector &CriticalPathRCs)
LLVM_ABI char & PostRASchedulerID
PostRAScheduler - This pass performs post register allocation scheduling.
Definition PostRASchedulerList.cpp:202
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
LLVM_ABI PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
FunctionAddr VTableAddr Count
CodeGenOptLevel
Code generation optimization level.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
auto count(R &&Range, const E &Element)
Wrapper function around std::count to count the number of times an element Element occurs in the give...
AntiDepBreaker * createCriticalAntiDepBreaker(MachineFunction &MFi, const RegisterClassInfo &RCI)
AAResults AliasAnalysis
Temporary typedef for legacy code that uses a generic AliasAnalysis pointer or reference.
LLVM_ABI Printable printMBBReference(const MachineBasicBlock &MBB)
Prints a machine basic block reference.