LLVM  4.0.0
SystemZHazardRecognizer.cpp
Go to the documentation of this file.
1 //=-- SystemZHazardRecognizer.h - SystemZ Hazard Recognizer -----*- C++ -*-===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file defines a hazard recognizer for the SystemZ scheduler.
11 //
12 // This class is used by the SystemZ scheduling strategy to maintain
13 // the state during scheduling, and provide cost functions for
14 // scheduling candidates. This includes:
15 //
16 // * Decoder grouping. A decoder group can maximally hold 3 uops, and
17 // instructions that always begin a new group should be scheduled when
18 // the current decoder group is empty.
19 // * Processor resources usage. It is beneficial to balance the use of
20 // resources.
21 //
22 // ===---------------------------------------------------------------------===//
23 
25 #include "llvm/ADT/Statistic.h"
26 
27 using namespace llvm;
28 
29 #define DEBUG_TYPE "misched"
30 
31 // This is the limit of processor resource usage at which the
32 // scheduler should try to look for other instructions (not using the
33 // critical resource).
34 static cl::opt<int> ProcResCostLim("procres-cost-lim", cl::Hidden,
35  cl::desc("The OOO window for processor "
36  "resources during scheduling."),
37  cl::init(8));
38 
41  SchedModel(nullptr) {}
42 
43 unsigned SystemZHazardRecognizer::
44 getNumDecoderSlots(SUnit *SU) const {
45  const MCSchedClassDesc *SC = DAG->getSchedClass(SU);
46  if (!SC->isValid())
47  return 0; // IMPLICIT_DEF / KILL -- will not make impact in output.
48 
49  if (SC->BeginGroup) {
50  if (!SC->EndGroup)
51  return 2; // Cracked instruction
52  else
53  return 3; // Expanded/group-alone instruction
54  }
55 
56  return 1; // Normal instruction
57 }
58 
59 unsigned SystemZHazardRecognizer::getCurrCycleIdx() {
60  unsigned Idx = CurrGroupSize;
61  if (GrpCount % 2)
62  Idx += 3;
63  return Idx;
64 }
65 
67 getHazardType(SUnit *m, int Stalls) {
68  return (fitsIntoCurrentGroup(m) ? NoHazard : Hazard);
69 }
70 
72  CurrGroupSize = 0;
73  clearProcResCounters();
74  GrpCount = 0;
75  LastFPdOpCycleIdx = UINT_MAX;
76  DEBUG(CurGroupDbg = "";);
77 }
78 
79 bool
80 SystemZHazardRecognizer::fitsIntoCurrentGroup(SUnit *SU) const {
81  const MCSchedClassDesc *SC = DAG->getSchedClass(SU);
82  if (!SC->isValid())
83  return true;
84 
85  // A cracked instruction only fits into schedule if the current
86  // group is empty.
87  if (SC->BeginGroup)
88  return (CurrGroupSize == 0);
89 
90  // Since a full group is handled immediately in EmitInstruction(),
91  // SU should fit into current group. NumSlots should be 1 or 0,
92  // since it is not a cracked or expanded instruction.
93  assert ((getNumDecoderSlots(SU) <= 1) && (CurrGroupSize < 3) &&
94  "Expected normal instruction to fit in non-full group!");
95 
96  return true;
97 }
98 
99 void SystemZHazardRecognizer::nextGroup(bool DbgOutput) {
100  if (CurrGroupSize > 0) {
101  DEBUG(dumpCurrGroup("Completed decode group"));
102  DEBUG(CurGroupDbg = "";);
103 
104  GrpCount++;
105 
106  // Reset counter for next group.
107  CurrGroupSize = 0;
108 
109  // Decrease counters for execution units by one.
110  for (unsigned i = 0; i < SchedModel->getNumProcResourceKinds(); ++i)
111  if (ProcResourceCounters[i] > 0)
112  ProcResourceCounters[i]--;
113 
114  // Clear CriticalResourceIdx if it is now below the threshold.
115  if (CriticalResourceIdx != UINT_MAX &&
116  (ProcResourceCounters[CriticalResourceIdx] <=
118  CriticalResourceIdx = UINT_MAX;
119  }
120 
121  DEBUG(if (DbgOutput)
123 }
124 
125 #ifndef NDEBUG // Debug output
127  OS << "SU(" << SU->NodeNum << "):";
128  OS << SchedModel->getInstrInfo()->getName(SU->getInstr()->getOpcode());
129 
130  const MCSchedClassDesc *SC = DAG->getSchedClass(SU);
131  if (!SC->isValid())
132  return;
133 
135  PI = SchedModel->getWriteProcResBegin(SC),
136  PE = SchedModel->getWriteProcResEnd(SC); PI != PE; ++PI) {
137  const MCProcResourceDesc &PRD =
138  *SchedModel->getProcResource(PI->ProcResourceIdx);
139  std::string FU(PRD.Name);
140  // trim e.g. Z13_FXaUnit -> FXa
141  FU = FU.substr(FU.find("_") + 1);
142  FU.resize(FU.find("Unit"));
143  OS << "/" << FU;
144 
145  if (PI->Cycles > 1)
146  OS << "(" << PI->Cycles << "cyc)";
147  }
148 
149  if (SC->NumMicroOps > 1)
150  OS << "/" << SC->NumMicroOps << "uops";
151  if (SC->BeginGroup && SC->EndGroup)
152  OS << "/GroupsAlone";
153  else if (SC->BeginGroup)
154  OS << "/BeginsGroup";
155  else if (SC->EndGroup)
156  OS << "/EndsGroup";
157  if (SU->isUnbuffered)
158  OS << "/Unbuffered";
159 }
160 
161 void SystemZHazardRecognizer::dumpCurrGroup(std::string Msg) const {
162  dbgs() << "+++ " << Msg;
163  dbgs() << ": ";
164 
165  if (CurGroupDbg.empty())
166  dbgs() << " <empty>\n";
167  else {
168  dbgs() << "{ " << CurGroupDbg << " }";
169  dbgs() << " (" << CurrGroupSize << " decoder slot"
170  << (CurrGroupSize > 1 ? "s":"")
171  << ")\n";
172  }
173 }
174 
176  bool any = false;
177 
178  for (unsigned i = 0; i < SchedModel->getNumProcResourceKinds(); ++i)
179  if (ProcResourceCounters[i] > 0) {
180  any = true;
181  break;
182  }
183 
184  if (!any)
185  return;
186 
187  dbgs() << "+++ Resource counters:\n";
188  for (unsigned i = 0; i < SchedModel->getNumProcResourceKinds(); ++i)
189  if (ProcResourceCounters[i] > 0) {
190  dbgs() << "+++ Extra schedule for execution unit "
191  << SchedModel->getProcResource(i)->Name
192  << ": " << ProcResourceCounters[i] << "\n";
193  any = true;
194  }
195 }
196 #endif //NDEBUG
197 
198 void SystemZHazardRecognizer::clearProcResCounters() {
199  ProcResourceCounters.assign(SchedModel->getNumProcResourceKinds(), 0);
200  CriticalResourceIdx = UINT_MAX;
201 }
202 
203 // Update state with SU as the next scheduled unit.
206  const MCSchedClassDesc *SC = DAG->getSchedClass(SU);
207  DEBUG( dumpCurrGroup("Decode group before emission"););
208 
209  // If scheduling an SU that must begin a new decoder group, move on
210  // to next group.
211  if (!fitsIntoCurrentGroup(SU))
212  nextGroup();
213 
214  DEBUG( dbgs() << "+++ HazardRecognizer emitting "; dumpSU(SU, dbgs());
215  dbgs() << "\n";
217  if (CurGroupDbg.length())
218  cgd << ", ";
219  dumpSU(SU, cgd););
220 
221  // After returning from a call, we don't know much about the state.
222  if (SU->getInstr()->isCall()) {
223  DEBUG (dbgs() << "+++ Clearing state after call.\n";);
224  clearProcResCounters();
225  LastFPdOpCycleIdx = UINT_MAX;
226  CurrGroupSize += getNumDecoderSlots(SU);
227  assert (CurrGroupSize <= 3);
228  nextGroup();
229  return;
230  }
231 
232  // Increase counter for execution unit(s).
234  PI = SchedModel->getWriteProcResBegin(SC),
235  PE = SchedModel->getWriteProcResEnd(SC); PI != PE; ++PI) {
236  // Don't handle FPd together with the other resources.
237  if (SchedModel->getProcResource(PI->ProcResourceIdx)->BufferSize == 1)
238  continue;
239  int &CurrCounter =
240  ProcResourceCounters[PI->ProcResourceIdx];
241  CurrCounter += PI->Cycles;
242  // Check if this is now the new critical resource.
243  if ((CurrCounter > ProcResCostLim) &&
244  (CriticalResourceIdx == UINT_MAX ||
245  (PI->ProcResourceIdx != CriticalResourceIdx &&
246  CurrCounter >
247  ProcResourceCounters[CriticalResourceIdx]))) {
248  DEBUG( dbgs() << "+++ New critical resource: "
249  << SchedModel->getProcResource(PI->ProcResourceIdx)->Name
250  << "\n";);
251  CriticalResourceIdx = PI->ProcResourceIdx;
252  }
253  }
254 
255  // Make note of an instruction that uses a blocking resource (FPd).
256  if (SU->isUnbuffered) {
257  LastFPdOpCycleIdx = getCurrCycleIdx();
258  DEBUG (dbgs() << "+++ Last FPd cycle index: "
259  << LastFPdOpCycleIdx << "\n";);
260  }
261 
262  // Insert SU into current group by increasing number of slots used
263  // in current group.
264  CurrGroupSize += getNumDecoderSlots(SU);
265  assert (CurrGroupSize <= 3);
266 
267  // Check if current group is now full/ended. If so, move on to next
268  // group to be ready to evaluate more candidates.
269  if (CurrGroupSize == 3 || SC->EndGroup)
270  nextGroup();
271 }
272 
274  const MCSchedClassDesc *SC = DAG->getSchedClass(SU);
275  if (!SC->isValid())
276  return 0;
277 
278  // If SU begins new group, it can either break a current group early
279  // or fit naturally if current group is empty (negative cost).
280  if (SC->BeginGroup) {
281  if (CurrGroupSize)
282  return 3 - CurrGroupSize;
283  return -1;
284  }
285 
286  // Similarly, a group-ending SU may either fit well (last in group), or
287  // end the group prematurely.
288  if (SC->EndGroup) {
289  unsigned resultingGroupSize =
290  (CurrGroupSize + getNumDecoderSlots(SU));
291  if (resultingGroupSize < 3)
292  return (3 - resultingGroupSize);
293  return -1;
294  }
295 
296  // Most instructions can be placed in any decoder slot.
297  return 0;
298 }
299 
300 bool SystemZHazardRecognizer::isFPdOpPreferred_distance(const SUnit *SU) {
301  assert (SU->isUnbuffered);
302  // If this is the first FPd op, it should be scheduled high.
303  if (LastFPdOpCycleIdx == UINT_MAX)
304  return true;
305  // If this is not the first PFd op, it should go into the other side
306  // of the processor to use the other FPd unit there. This should
307  // generally happen if two FPd ops are placed with 2 other
308  // instructions between them (modulo 6).
309  if (LastFPdOpCycleIdx > getCurrCycleIdx())
310  return ((LastFPdOpCycleIdx - getCurrCycleIdx()) == 3);
311  return ((getCurrCycleIdx() - LastFPdOpCycleIdx) == 3);
312 }
313 
316  int Cost = 0;
317 
318  const MCSchedClassDesc *SC = DAG->getSchedClass(SU);
319  if (!SC->isValid())
320  return 0;
321 
322  // For a FPd op, either return min or max value as indicated by the
323  // distance to any prior FPd op.
324  if (SU->isUnbuffered)
325  Cost = (isFPdOpPreferred_distance(SU) ? INT_MIN : INT_MAX);
326  // For other instructions, give a cost to the use of the critical resource.
327  else if (CriticalResourceIdx != UINT_MAX) {
329  PI = SchedModel->getWriteProcResBegin(SC),
330  PE = SchedModel->getWriteProcResEnd(SC); PI != PE; ++PI)
331  if (PI->ProcResourceIdx == CriticalResourceIdx)
332  Cost = PI->Cycles;
333  }
334 
335  return Cost;
336 }
337 
size_t i
unsigned short NumMicroOps
Definition: MCSchedule.h:108
MachineInstr * getInstr() const
getInstr - Return the representative MachineInstr for this SUnit.
Definition: ScheduleDAG.h:389
void dumpCurrGroup(std::string Msg="") const
const MCSchedClassDesc * getSchedClass(SUnit *SU) const
Resolve and cache a resolved scheduling class for an SUnit.
const TargetInstrInfo * getInstrInfo() const
TargetInstrInfo getter.
int groupingCost(SUnit *SU) const
Return the cost of decoder grouping for SU.
void Reset() override
Reset - This callback is invoked when a new block of instructions is about to be schedule.
StringRef getName(unsigned Opcode) const
Returns the name for the instructions with the given opcode.
Definition: MCInstrInfo.h:51
SystemZHazardRecognizer(const MachineSchedContext *C)
void assign(size_type NumElts, const T &Elt)
Definition: SmallVector.h:418
HazardType getHazardType(SUnit *m, int Stalls=0) override
getHazardType - Return the hazard type of emitting this node.
void EmitInstruction(SUnit *SU) override
EmitInstruction - This callback is invoked when an instruction is emitted, to advance the hazard stat...
bool isValid() const
Definition: MCSchedule.h:118
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
Definition: MachineInstr.h:273
bool isUnbuffered
Definition: ScheduleDAG.h:290
initializer< Ty > init(const Ty &Val)
Definition: CommandLine.h:395
Identify one of the processor resource kinds consumed by a particular scheduling class for the specif...
Definition: MCSchedule.h:55
Summarize the scheduling resources required for an instruction of a particular scheduling class...
Definition: MCSchedule.h:101
int resourcesCost(SUnit *SU)
Return the cost of SU in regards to processor resources usage.
unsigned getNumProcResourceKinds() const
Get the number of kinds of resources for this target.
ProcResIter getWriteProcResEnd(const MCSchedClassDesc *SC) const
const MCProcResourceDesc * getProcResource(unsigned PIdx) const
Get a processor resource by ID for convenience.
Define a kind of processor resource that will be modeled by the scheduler.
Definition: MCSchedule.h:26
CHAIN = SC CHAIN, Imm128 - System call.
static GCRegistry::Add< ShadowStackGC > C("shadow-stack","Very portable GC for uncooperative code generators")
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:132
MachineSchedContext provides enough context from the MachineScheduler pass for the target to instanti...
bool isCall(QueryType Type=AnyInBundle) const
Definition: MachineInstr.h:424
unsigned NodeNum
Definition: ScheduleDAG.h:266
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
A raw_ostream that writes to an std::string.
Definition: raw_ostream.h:463
static cl::opt< int > ProcResCostLim("procres-cost-lim", cl::Hidden, cl::desc("The OOO window for processor ""resources during scheduling."), cl::init(8))
This class implements an extremely fast bulk output stream that can only output to a stream...
Definition: raw_ostream.h:44
#define DEBUG(X)
Definition: Debug.h:100
ProcResIter getWriteProcResBegin(const MCSchedClassDesc *SC) const
SUnit - Scheduling unit. This is a node in the scheduling DAG.
Definition: ScheduleDAG.h:244
void dumpSU(SUnit *SU, raw_ostream &OS) const