1*06f32e7eSjoerg //==- SystemZMachineScheduler.h - SystemZ Scheduler Interface ----*- C++ -*-==//
2*06f32e7eSjoerg //
3*06f32e7eSjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*06f32e7eSjoerg // See https://llvm.org/LICENSE.txt for license information.
5*06f32e7eSjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*06f32e7eSjoerg //
7*06f32e7eSjoerg //===----------------------------------------------------------------------===//
8*06f32e7eSjoerg //
9*06f32e7eSjoerg // -------------------------- Post RA scheduling ---------------------------- //
10*06f32e7eSjoerg // SystemZPostRASchedStrategy is a scheduling strategy which is plugged into
11*06f32e7eSjoerg // the MachineScheduler. It has a sorted Available set of SUs and a pickNode()
12*06f32e7eSjoerg // implementation that looks to optimize decoder grouping and balance the
13*06f32e7eSjoerg // usage of processor resources. Scheduler states are saved for the end
14*06f32e7eSjoerg // region of each MBB, so that a successor block can learn from it.
15*06f32e7eSjoerg //===----------------------------------------------------------------------===//
16*06f32e7eSjoerg 
17*06f32e7eSjoerg #include "SystemZHazardRecognizer.h"
18*06f32e7eSjoerg #include "llvm/CodeGen/MachineScheduler.h"
19*06f32e7eSjoerg #include "llvm/CodeGen/ScheduleDAG.h"
20*06f32e7eSjoerg #include <set>
21*06f32e7eSjoerg 
22*06f32e7eSjoerg #ifndef LLVM_LIB_TARGET_SYSTEMZ_SYSTEMZMACHINESCHEDULER_H
23*06f32e7eSjoerg #define LLVM_LIB_TARGET_SYSTEMZ_SYSTEMZMACHINESCHEDULER_H
24*06f32e7eSjoerg 
25*06f32e7eSjoerg using namespace llvm;
26*06f32e7eSjoerg 
27*06f32e7eSjoerg namespace llvm {
28*06f32e7eSjoerg 
29*06f32e7eSjoerg /// A MachineSchedStrategy implementation for SystemZ post RA scheduling.
30*06f32e7eSjoerg class SystemZPostRASchedStrategy : public MachineSchedStrategy {
31*06f32e7eSjoerg 
32*06f32e7eSjoerg   const MachineLoopInfo *MLI;
33*06f32e7eSjoerg   const SystemZInstrInfo *TII;
34*06f32e7eSjoerg 
35*06f32e7eSjoerg   // A SchedModel is needed before any DAG is built while advancing past
36*06f32e7eSjoerg   // non-scheduled instructions, so it would not always be possible to call
37*06f32e7eSjoerg   // DAG->getSchedClass(SU).
38*06f32e7eSjoerg   TargetSchedModel SchedModel;
39*06f32e7eSjoerg 
40*06f32e7eSjoerg   /// A candidate during instruction evaluation.
41*06f32e7eSjoerg   struct Candidate {
42*06f32e7eSjoerg     SUnit *SU = nullptr;
43*06f32e7eSjoerg 
44*06f32e7eSjoerg     /// The decoding cost.
45*06f32e7eSjoerg     int GroupingCost = 0;
46*06f32e7eSjoerg 
47*06f32e7eSjoerg     /// The processor resources cost.
48*06f32e7eSjoerg     int ResourcesCost = 0;
49*06f32e7eSjoerg 
50*06f32e7eSjoerg     Candidate() = default;
51*06f32e7eSjoerg     Candidate(SUnit *SU_, SystemZHazardRecognizer &HazardRec);
52*06f32e7eSjoerg 
53*06f32e7eSjoerg     // Compare two candidates.
54*06f32e7eSjoerg     bool operator<(const Candidate &other);
55*06f32e7eSjoerg 
56*06f32e7eSjoerg     // Check if this node is free of cost ("as good as any").
noCostCandidate57*06f32e7eSjoerg     bool noCost() const {
58*06f32e7eSjoerg       return (GroupingCost <= 0 && !ResourcesCost);
59*06f32e7eSjoerg     }
60*06f32e7eSjoerg 
61*06f32e7eSjoerg #ifndef NDEBUG
dumpCostsCandidate62*06f32e7eSjoerg     void dumpCosts() {
63*06f32e7eSjoerg       if (GroupingCost != 0)
64*06f32e7eSjoerg         dbgs() << "  Grouping cost:" << GroupingCost;
65*06f32e7eSjoerg       if (ResourcesCost != 0)
66*06f32e7eSjoerg         dbgs() << "  Resource cost:" << ResourcesCost;
67*06f32e7eSjoerg     }
68*06f32e7eSjoerg #endif
69*06f32e7eSjoerg   };
70*06f32e7eSjoerg 
71*06f32e7eSjoerg   // A sorter for the Available set that makes sure that SUs are considered
72*06f32e7eSjoerg   // in the best order.
73*06f32e7eSjoerg   struct SUSorter {
operatorSUSorter74*06f32e7eSjoerg     bool operator() (SUnit *lhs, SUnit *rhs) const {
75*06f32e7eSjoerg       if (lhs->isScheduleHigh && !rhs->isScheduleHigh)
76*06f32e7eSjoerg         return true;
77*06f32e7eSjoerg       if (!lhs->isScheduleHigh && rhs->isScheduleHigh)
78*06f32e7eSjoerg         return false;
79*06f32e7eSjoerg 
80*06f32e7eSjoerg       if (lhs->getHeight() > rhs->getHeight())
81*06f32e7eSjoerg         return true;
82*06f32e7eSjoerg       else if (lhs->getHeight() < rhs->getHeight())
83*06f32e7eSjoerg         return false;
84*06f32e7eSjoerg 
85*06f32e7eSjoerg       return (lhs->NodeNum < rhs->NodeNum);
86*06f32e7eSjoerg     }
87*06f32e7eSjoerg   };
88*06f32e7eSjoerg   // A set of SUs with a sorter and dump method.
89*06f32e7eSjoerg   struct SUSet : std::set<SUnit*, SUSorter> {
90*06f32e7eSjoerg     #ifndef NDEBUG
91*06f32e7eSjoerg     void dump(SystemZHazardRecognizer &HazardRec) const;
92*06f32e7eSjoerg     #endif
93*06f32e7eSjoerg   };
94*06f32e7eSjoerg 
95*06f32e7eSjoerg   /// The set of available SUs to schedule next.
96*06f32e7eSjoerg   SUSet Available;
97*06f32e7eSjoerg 
98*06f32e7eSjoerg   /// Current MBB
99*06f32e7eSjoerg   MachineBasicBlock *MBB;
100*06f32e7eSjoerg 
101*06f32e7eSjoerg   /// Maintain hazard recognizers for all blocks, so that the scheduler state
102*06f32e7eSjoerg   /// can be maintained past BB boundaries when appropariate.
103*06f32e7eSjoerg   typedef std::map<MachineBasicBlock*, SystemZHazardRecognizer*> MBB2HazRec;
104*06f32e7eSjoerg   MBB2HazRec SchedStates;
105*06f32e7eSjoerg 
106*06f32e7eSjoerg   /// Pointer to the HazardRecognizer that tracks the scheduler state for
107*06f32e7eSjoerg   /// the current region.
108*06f32e7eSjoerg   SystemZHazardRecognizer *HazardRec;
109*06f32e7eSjoerg 
110*06f32e7eSjoerg   /// Update the scheduler state by emitting (non-scheduled) instructions
111*06f32e7eSjoerg   /// up to, but not including, NextBegin.
112*06f32e7eSjoerg   void advanceTo(MachineBasicBlock::iterator NextBegin);
113*06f32e7eSjoerg 
114*06f32e7eSjoerg public:
115*06f32e7eSjoerg   SystemZPostRASchedStrategy(const MachineSchedContext *C);
116*06f32e7eSjoerg   virtual ~SystemZPostRASchedStrategy();
117*06f32e7eSjoerg 
118*06f32e7eSjoerg   /// Called for a region before scheduling.
119*06f32e7eSjoerg   void initPolicy(MachineBasicBlock::iterator Begin,
120*06f32e7eSjoerg                   MachineBasicBlock::iterator End,
121*06f32e7eSjoerg                   unsigned NumRegionInstrs) override;
122*06f32e7eSjoerg 
123*06f32e7eSjoerg   /// PostRA scheduling does not track pressure.
shouldTrackPressure()124*06f32e7eSjoerg   bool shouldTrackPressure() const override { return false; }
125*06f32e7eSjoerg 
126*06f32e7eSjoerg   // Process scheduling regions top-down so that scheduler states can be
127*06f32e7eSjoerg   // transferrred over scheduling boundaries.
doMBBSchedRegionsTopDown()128*06f32e7eSjoerg   bool doMBBSchedRegionsTopDown() const override { return true; }
129*06f32e7eSjoerg 
130*06f32e7eSjoerg   void initialize(ScheduleDAGMI *dag) override;
131*06f32e7eSjoerg 
132*06f32e7eSjoerg   /// Tell the strategy that MBB is about to be processed.
133*06f32e7eSjoerg   void enterMBB(MachineBasicBlock *NextMBB) override;
134*06f32e7eSjoerg 
135*06f32e7eSjoerg   /// Tell the strategy that current MBB is done.
136*06f32e7eSjoerg   void leaveMBB() override;
137*06f32e7eSjoerg 
138*06f32e7eSjoerg   /// Pick the next node to schedule, or return NULL.
139*06f32e7eSjoerg   SUnit *pickNode(bool &IsTopNode) override;
140*06f32e7eSjoerg 
141*06f32e7eSjoerg   /// ScheduleDAGMI has scheduled an instruction - tell HazardRec
142*06f32e7eSjoerg   /// about it.
143*06f32e7eSjoerg   void schedNode(SUnit *SU, bool IsTopNode) override;
144*06f32e7eSjoerg 
145*06f32e7eSjoerg   /// SU has had all predecessor dependencies resolved. Put it into
146*06f32e7eSjoerg   /// Available.
147*06f32e7eSjoerg   void releaseTopNode(SUnit *SU) override;
148*06f32e7eSjoerg 
149*06f32e7eSjoerg   /// Currently only scheduling top-down, so this method is empty.
releaseBottomNode(SUnit * SU)150*06f32e7eSjoerg   void releaseBottomNode(SUnit *SU) override {};
151*06f32e7eSjoerg };
152*06f32e7eSjoerg 
153*06f32e7eSjoerg } // end namespace llvm
154*06f32e7eSjoerg 
155*06f32e7eSjoerg #endif // LLVM_LIB_TARGET_SYSTEMZ_SYSTEMZMACHINESCHEDULER_H
156