xref: /freebsd/contrib/llvm-project/llvm/lib/Target/SystemZ/SystemZHazardRecognizer.h (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
1*0b57cec5SDimitry Andric //=-- SystemZHazardRecognizer.h - SystemZ Hazard Recognizer -----*- C++ -*-===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric //
9*0b57cec5SDimitry Andric // This file declares a hazard recognizer for the SystemZ scheduler.
10*0b57cec5SDimitry Andric //
11*0b57cec5SDimitry Andric // This class is used by the SystemZ scheduling strategy to maintain
12*0b57cec5SDimitry Andric // the state during scheduling, and provide cost functions for
13*0b57cec5SDimitry Andric // scheduling candidates. This includes:
14*0b57cec5SDimitry Andric //
15*0b57cec5SDimitry Andric // * Decoder grouping. A decoder group can maximally hold 3 uops, and
16*0b57cec5SDimitry Andric // instructions that always begin a new group should be scheduled when
17*0b57cec5SDimitry Andric // the current decoder group is empty.
18*0b57cec5SDimitry Andric // * Processor resources usage. It is beneficial to balance the use of
19*0b57cec5SDimitry Andric // resources.
20*0b57cec5SDimitry Andric //
21*0b57cec5SDimitry Andric // A goal is to consider all instructions, also those outside of any
22*0b57cec5SDimitry Andric // scheduling region. Such instructions are "advanced" past and include
23*0b57cec5SDimitry Andric // single instructions before a scheduling region, branches etc.
24*0b57cec5SDimitry Andric //
25*0b57cec5SDimitry Andric // A block that has only one predecessor continues scheduling with the state
26*0b57cec5SDimitry Andric // of it (which may be updated by emitting branches).
27*0b57cec5SDimitry Andric //
28*0b57cec5SDimitry Andric // ===---------------------------------------------------------------------===//
29*0b57cec5SDimitry Andric 
30*0b57cec5SDimitry Andric #ifndef LLVM_LIB_TARGET_SYSTEMZ_SYSTEMZHAZARDRECOGNIZER_H
31*0b57cec5SDimitry Andric #define LLVM_LIB_TARGET_SYSTEMZ_SYSTEMZHAZARDRECOGNIZER_H
32*0b57cec5SDimitry Andric 
33*0b57cec5SDimitry Andric #include "SystemZSubtarget.h"
34*0b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h"
35*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
36*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineScheduler.h"
37*0b57cec5SDimitry Andric #include "llvm/CodeGen/ScheduleHazardRecognizer.h"
38*0b57cec5SDimitry Andric #include "llvm/MC/MCInstrDesc.h"
39*0b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
40*0b57cec5SDimitry Andric #include <string>
41*0b57cec5SDimitry Andric 
42*0b57cec5SDimitry Andric namespace llvm {
43*0b57cec5SDimitry Andric 
44*0b57cec5SDimitry Andric /// SystemZHazardRecognizer maintains the state for one MBB during scheduling.
45*0b57cec5SDimitry Andric class SystemZHazardRecognizer : public ScheduleHazardRecognizer {
46*0b57cec5SDimitry Andric 
47*0b57cec5SDimitry Andric   const SystemZInstrInfo *TII;
48*0b57cec5SDimitry Andric   const TargetSchedModel *SchedModel;
49*0b57cec5SDimitry Andric 
50*0b57cec5SDimitry Andric   /// Keep track of the number of decoder slots used in the current
51*0b57cec5SDimitry Andric   /// decoder group.
52*0b57cec5SDimitry Andric   unsigned CurrGroupSize;
53*0b57cec5SDimitry Andric 
54*0b57cec5SDimitry Andric   /// True if an instruction with four reg operands have been scheduled into
55*0b57cec5SDimitry Andric   /// the current decoder group.
56*0b57cec5SDimitry Andric   bool CurrGroupHas4RegOps;
57*0b57cec5SDimitry Andric 
58*0b57cec5SDimitry Andric   /// The tracking of resources here are quite similar to the common
59*0b57cec5SDimitry Andric   /// code use of a critical resource. However, z13 differs in the way
60*0b57cec5SDimitry Andric   /// that it has two processor sides which may be interesting to
61*0b57cec5SDimitry Andric   /// model in the future (a work in progress).
62*0b57cec5SDimitry Andric 
63*0b57cec5SDimitry Andric   /// Counters for the number of uops scheduled per processor
64*0b57cec5SDimitry Andric   /// resource.
65*0b57cec5SDimitry Andric   SmallVector<int, 0> ProcResourceCounters;
66*0b57cec5SDimitry Andric 
67*0b57cec5SDimitry Andric   /// This is the resource with the greatest queue, which the
68*0b57cec5SDimitry Andric   /// scheduler tries to avoid.
69*0b57cec5SDimitry Andric   unsigned CriticalResourceIdx;
70*0b57cec5SDimitry Andric 
71*0b57cec5SDimitry Andric   /// Return the number of decoder slots MI requires.
72*0b57cec5SDimitry Andric   inline unsigned getNumDecoderSlots(SUnit *SU) const;
73*0b57cec5SDimitry Andric 
74*0b57cec5SDimitry Andric   /// Return true if MI fits into current decoder group.
75*0b57cec5SDimitry Andric   bool fitsIntoCurrentGroup(SUnit *SU) const;
76*0b57cec5SDimitry Andric 
77*0b57cec5SDimitry Andric   /// Return true if this instruction has four register operands.
78*0b57cec5SDimitry Andric   bool has4RegOps(const MachineInstr *MI) const;
79*0b57cec5SDimitry Andric 
80*0b57cec5SDimitry Andric   /// Two decoder groups per cycle are formed (for z13), meaning 2x3
81*0b57cec5SDimitry Andric   /// instructions. This function returns a number between 0 and 5,
82*0b57cec5SDimitry Andric   /// representing the current decoder slot of the current cycle.  If an SU
83*0b57cec5SDimitry Andric   /// is passed which will begin a new decoder group, the returned value is
84*0b57cec5SDimitry Andric   /// the cycle index of the next group.
85*0b57cec5SDimitry Andric   unsigned getCurrCycleIdx(SUnit *SU = nullptr) const;
86*0b57cec5SDimitry Andric 
87*0b57cec5SDimitry Andric   /// LastFPdOpCycleIdx stores the numbeer returned by getCurrCycleIdx()
88*0b57cec5SDimitry Andric   /// when a stalling operation is scheduled (which uses the FPd resource).
89*0b57cec5SDimitry Andric   unsigned LastFPdOpCycleIdx;
90*0b57cec5SDimitry Andric 
91*0b57cec5SDimitry Andric   /// A counter of decoder groups scheduled.
92*0b57cec5SDimitry Andric   unsigned GrpCount;
93*0b57cec5SDimitry Andric 
94*0b57cec5SDimitry Andric   unsigned getCurrGroupSize() {return CurrGroupSize;};
95*0b57cec5SDimitry Andric 
96*0b57cec5SDimitry Andric   /// Start next decoder group.
97*0b57cec5SDimitry Andric   void nextGroup();
98*0b57cec5SDimitry Andric 
99*0b57cec5SDimitry Andric   /// Clear all counters for processor resources.
100*0b57cec5SDimitry Andric   void clearProcResCounters();
101*0b57cec5SDimitry Andric 
102*0b57cec5SDimitry Andric   /// With the goal of alternating processor sides for stalling (FPd)
103*0b57cec5SDimitry Andric   /// ops, return true if it seems good to schedule an FPd op next.
104*0b57cec5SDimitry Andric   bool isFPdOpPreferred_distance(SUnit *SU) const;
105*0b57cec5SDimitry Andric 
106*0b57cec5SDimitry Andric   /// Last emitted instruction or nullptr.
107*0b57cec5SDimitry Andric   MachineInstr *LastEmittedMI;
108*0b57cec5SDimitry Andric 
109*0b57cec5SDimitry Andric public:
110*0b57cec5SDimitry Andric   SystemZHazardRecognizer(const SystemZInstrInfo *tii,
111*0b57cec5SDimitry Andric                           const TargetSchedModel *SM)
112*0b57cec5SDimitry Andric       : TII(tii), SchedModel(SM) {
113*0b57cec5SDimitry Andric     Reset();
114*0b57cec5SDimitry Andric   }
115*0b57cec5SDimitry Andric 
116*0b57cec5SDimitry Andric   HazardType getHazardType(SUnit *m, int Stalls = 0) override;
117*0b57cec5SDimitry Andric   void Reset() override;
118*0b57cec5SDimitry Andric   void EmitInstruction(SUnit *SU) override;
119*0b57cec5SDimitry Andric 
120*0b57cec5SDimitry Andric   /// Resolves and cache a resolved scheduling class for an SUnit.
121*0b57cec5SDimitry Andric   const MCSchedClassDesc *getSchedClass(SUnit *SU) const {
122*0b57cec5SDimitry Andric     if (!SU->SchedClass && SchedModel->hasInstrSchedModel())
123*0b57cec5SDimitry Andric       SU->SchedClass = SchedModel->resolveSchedClass(SU->getInstr());
124*0b57cec5SDimitry Andric     return SU->SchedClass;
125*0b57cec5SDimitry Andric   }
126*0b57cec5SDimitry Andric 
127*0b57cec5SDimitry Andric   /// Wrap a non-scheduled instruction in an SU and emit it.
128*0b57cec5SDimitry Andric   void emitInstruction(MachineInstr *MI, bool TakenBranch = false);
129*0b57cec5SDimitry Andric 
130*0b57cec5SDimitry Andric   // Cost functions used by SystemZPostRASchedStrategy while
131*0b57cec5SDimitry Andric   // evaluating candidates.
132*0b57cec5SDimitry Andric 
133*0b57cec5SDimitry Andric   /// Return the cost of decoder grouping for SU. If SU must start a
134*0b57cec5SDimitry Andric   /// new decoder group, this is negative if this fits the schedule or
135*0b57cec5SDimitry Andric   /// positive if it would mean ending a group prematurely. For normal
136*0b57cec5SDimitry Andric   /// instructions this returns 0.
137*0b57cec5SDimitry Andric   int groupingCost(SUnit *SU) const;
138*0b57cec5SDimitry Andric 
139*0b57cec5SDimitry Andric   /// Return the cost of SU in regards to processor resources usage.
140*0b57cec5SDimitry Andric   /// A positive value means it would be better to wait with SU, while
141*0b57cec5SDimitry Andric   /// a negative value means it would be good to schedule SU next.
142*0b57cec5SDimitry Andric   int resourcesCost(SUnit *SU);
143*0b57cec5SDimitry Andric 
144*0b57cec5SDimitry Andric #ifndef NDEBUG
145*0b57cec5SDimitry Andric   // Debug dumping.
146*0b57cec5SDimitry Andric   std::string CurGroupDbg; // current group as text
147*0b57cec5SDimitry Andric   void dumpSU(SUnit *SU, raw_ostream &OS) const;
148*0b57cec5SDimitry Andric   void dumpCurrGroup(std::string Msg = "") const;
149*0b57cec5SDimitry Andric   void dumpProcResourceCounters() const;
150*0b57cec5SDimitry Andric   void dumpState() const;
151*0b57cec5SDimitry Andric #endif
152*0b57cec5SDimitry Andric 
153*0b57cec5SDimitry Andric   MachineBasicBlock::iterator getLastEmittedMI() { return LastEmittedMI; }
154*0b57cec5SDimitry Andric 
155*0b57cec5SDimitry Andric   /// Copy counters from end of single predecessor.
156*0b57cec5SDimitry Andric   void copyState(SystemZHazardRecognizer *Incoming);
157*0b57cec5SDimitry Andric };
158*0b57cec5SDimitry Andric 
159*0b57cec5SDimitry Andric } // namespace llvm
160*0b57cec5SDimitry Andric 
161*0b57cec5SDimitry Andric #endif /* LLVM_LIB_TARGET_SYSTEMZ_SYSTEMZHAZARDRECOGNIZER_H */
162