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