]>
Commit | Line | Data |
---|---|---|
223e47cc LB |
1 | //===-- PPCHazardRecognizers.cpp - PowerPC Hazard Recognizer Impls --------===// |
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 implements hazard recognizers for scheduling on PowerPC processors. | |
11 | // | |
12 | //===----------------------------------------------------------------------===// | |
13 | ||
223e47cc LB |
14 | #include "PPCHazardRecognizers.h" |
15 | #include "PPC.h" | |
16 | #include "PPCInstrInfo.h" | |
1a4d82fc | 17 | #include "PPCTargetMachine.h" |
223e47cc LB |
18 | #include "llvm/CodeGen/ScheduleDAG.h" |
19 | #include "llvm/Support/Debug.h" | |
20 | #include "llvm/Support/ErrorHandling.h" | |
21 | #include "llvm/Support/raw_ostream.h" | |
22 | using namespace llvm; | |
23 | ||
1a4d82fc JJ |
24 | #define DEBUG_TYPE "pre-RA-sched" |
25 | ||
26 | bool PPCDispatchGroupSBHazardRecognizer::isLoadAfterStore(SUnit *SU) { | |
27 | // FIXME: Move this. | |
28 | if (isBCTRAfterSet(SU)) | |
29 | return true; | |
30 | ||
223e47cc LB |
31 | const MCInstrDesc *MCID = DAG->getInstrDesc(SU); |
32 | if (!MCID) | |
1a4d82fc JJ |
33 | return false; |
34 | ||
35 | if (!MCID->mayLoad()) | |
36 | return false; | |
37 | ||
38 | // SU is a load; for any predecessors in this dispatch group, that are stores, | |
39 | // and with which we have an ordering dependency, return true. | |
40 | for (unsigned i = 0, ie = (unsigned) SU->Preds.size(); i != ie; ++i) { | |
41 | const MCInstrDesc *PredMCID = DAG->getInstrDesc(SU->Preds[i].getSUnit()); | |
42 | if (!PredMCID || !PredMCID->mayStore()) | |
43 | continue; | |
44 | ||
45 | if (!SU->Preds[i].isNormalMemory() && !SU->Preds[i].isBarrier()) | |
46 | continue; | |
47 | ||
48 | for (unsigned j = 0, je = CurGroup.size(); j != je; ++j) | |
49 | if (SU->Preds[i].getSUnit() == CurGroup[j]) | |
50 | return true; | |
51 | } | |
52 | ||
53 | return false; | |
54 | } | |
55 | ||
56 | bool PPCDispatchGroupSBHazardRecognizer::isBCTRAfterSet(SUnit *SU) { | |
57 | const MCInstrDesc *MCID = DAG->getInstrDesc(SU); | |
58 | if (!MCID) | |
59 | return false; | |
60 | ||
61 | if (!MCID->isBranch()) | |
62 | return false; | |
63 | ||
64 | // SU is a branch; for any predecessors in this dispatch group, with which we | |
65 | // have a data dependence and set the counter register, return true. | |
66 | for (unsigned i = 0, ie = (unsigned) SU->Preds.size(); i != ie; ++i) { | |
67 | const MCInstrDesc *PredMCID = DAG->getInstrDesc(SU->Preds[i].getSUnit()); | |
68 | if (!PredMCID || PredMCID->getSchedClass() != PPC::Sched::IIC_SprMTSPR) | |
69 | continue; | |
70 | ||
71 | if (SU->Preds[i].isCtrl()) | |
72 | continue; | |
223e47cc | 73 | |
1a4d82fc JJ |
74 | for (unsigned j = 0, je = CurGroup.size(); j != je; ++j) |
75 | if (SU->Preds[i].getSUnit() == CurGroup[j]) | |
76 | return true; | |
77 | } | |
78 | ||
79 | return false; | |
80 | } | |
81 | ||
82 | // FIXME: Remove this when we don't need this: | |
83 | namespace llvm { namespace PPC { extern int getNonRecordFormOpcode(uint16_t); } } | |
84 | ||
85 | // FIXME: A lot of code in PPCDispatchGroupSBHazardRecognizer is P7 specific. | |
86 | ||
87 | bool PPCDispatchGroupSBHazardRecognizer::mustComeFirst(const MCInstrDesc *MCID, | |
88 | unsigned &NSlots) { | |
89 | // FIXME: Indirectly, this information is contained in the itinerary, and | |
90 | // we should derive it from there instead of separately specifying it | |
91 | // here. | |
92 | unsigned IIC = MCID->getSchedClass(); | |
93 | switch (IIC) { | |
94 | default: | |
95 | NSlots = 1; | |
96 | break; | |
97 | case PPC::Sched::IIC_IntDivW: | |
98 | case PPC::Sched::IIC_IntDivD: | |
99 | case PPC::Sched::IIC_LdStLoadUpd: | |
100 | case PPC::Sched::IIC_LdStLDU: | |
101 | case PPC::Sched::IIC_LdStLFDU: | |
102 | case PPC::Sched::IIC_LdStLFDUX: | |
103 | case PPC::Sched::IIC_LdStLHA: | |
104 | case PPC::Sched::IIC_LdStLHAU: | |
105 | case PPC::Sched::IIC_LdStLWA: | |
106 | case PPC::Sched::IIC_LdStSTDU: | |
107 | case PPC::Sched::IIC_LdStSTFDU: | |
108 | NSlots = 2; | |
109 | break; | |
110 | case PPC::Sched::IIC_LdStLoadUpdX: | |
111 | case PPC::Sched::IIC_LdStLDUX: | |
112 | case PPC::Sched::IIC_LdStLHAUX: | |
113 | case PPC::Sched::IIC_LdStLWARX: | |
114 | case PPC::Sched::IIC_LdStLDARX: | |
115 | case PPC::Sched::IIC_LdStSTDUX: | |
116 | case PPC::Sched::IIC_LdStSTDCX: | |
117 | case PPC::Sched::IIC_LdStSTWCX: | |
118 | case PPC::Sched::IIC_BrMCRX: // mtcr | |
119 | // FIXME: Add sync/isync (here and in the itinerary). | |
120 | NSlots = 4; | |
121 | break; | |
122 | } | |
123 | ||
124 | // FIXME: record-form instructions need a different itinerary class. | |
125 | if (NSlots == 1 && PPC::getNonRecordFormOpcode(MCID->getOpcode()) != -1) | |
126 | NSlots = 2; | |
127 | ||
128 | switch (IIC) { | |
129 | default: | |
130 | // All multi-slot instructions must come first. | |
131 | return NSlots > 1; | |
132 | case PPC::Sched::IIC_BrCR: // cr logicals | |
133 | case PPC::Sched::IIC_SprMFCR: | |
134 | case PPC::Sched::IIC_SprMFCRF: | |
135 | case PPC::Sched::IIC_SprMTSPR: | |
136 | return true; | |
137 | } | |
223e47cc LB |
138 | } |
139 | ||
140 | ScheduleHazardRecognizer::HazardType | |
1a4d82fc JJ |
141 | PPCDispatchGroupSBHazardRecognizer::getHazardType(SUnit *SU, int Stalls) { |
142 | if (Stalls == 0 && isLoadAfterStore(SU)) | |
143 | return NoopHazard; | |
144 | ||
223e47cc LB |
145 | return ScoreboardHazardRecognizer::getHazardType(SU, Stalls); |
146 | } | |
147 | ||
1a4d82fc JJ |
148 | bool PPCDispatchGroupSBHazardRecognizer::ShouldPreferAnother(SUnit *SU) { |
149 | const MCInstrDesc *MCID = DAG->getInstrDesc(SU); | |
150 | unsigned NSlots; | |
151 | if (MCID && mustComeFirst(MCID, NSlots) && CurSlots) | |
152 | return true; | |
153 | ||
154 | return ScoreboardHazardRecognizer::ShouldPreferAnother(SU); | |
223e47cc LB |
155 | } |
156 | ||
1a4d82fc JJ |
157 | unsigned PPCDispatchGroupSBHazardRecognizer::PreEmitNoops(SUnit *SU) { |
158 | // We only need to fill out a maximum of 5 slots here: The 6th slot could | |
159 | // only be a second branch, and otherwise the next instruction will start a | |
160 | // new group. | |
161 | if (isLoadAfterStore(SU) && CurSlots < 6) { | |
162 | unsigned Directive = | |
163 | DAG->TM.getSubtarget<PPCSubtarget>().getDarwinDirective(); | |
164 | // If we're using a special group-terminating nop, then we need only one. | |
165 | if (Directive == PPC::DIR_PWR6 || Directive == PPC::DIR_PWR7 || | |
166 | Directive == PPC::DIR_PWR8 ) | |
167 | return 1; | |
168 | ||
169 | return 5 - CurSlots; | |
170 | } | |
171 | ||
172 | return ScoreboardHazardRecognizer::PreEmitNoops(SU); | |
173 | } | |
174 | ||
175 | void PPCDispatchGroupSBHazardRecognizer::EmitInstruction(SUnit *SU) { | |
176 | const MCInstrDesc *MCID = DAG->getInstrDesc(SU); | |
177 | if (MCID) { | |
178 | if (CurSlots == 5 || (MCID->isBranch() && CurBranches == 1)) { | |
179 | CurGroup.clear(); | |
180 | CurSlots = CurBranches = 0; | |
181 | } else { | |
182 | DEBUG(dbgs() << "**** Adding to dispatch group: SU(" << | |
183 | SU->NodeNum << "): "); | |
184 | DEBUG(DAG->dumpNode(SU)); | |
185 | ||
186 | unsigned NSlots; | |
187 | bool MustBeFirst = mustComeFirst(MCID, NSlots); | |
188 | ||
189 | // If this instruction must come first, but does not, then it starts a | |
190 | // new group. | |
191 | if (MustBeFirst && CurSlots) { | |
192 | CurSlots = CurBranches = 0; | |
193 | CurGroup.clear(); | |
194 | } | |
195 | ||
196 | CurSlots += NSlots; | |
197 | CurGroup.push_back(SU); | |
198 | ||
199 | if (MCID->isBranch()) | |
200 | ++CurBranches; | |
201 | } | |
202 | } | |
203 | ||
204 | return ScoreboardHazardRecognizer::EmitInstruction(SU); | |
205 | } | |
206 | ||
207 | void PPCDispatchGroupSBHazardRecognizer::AdvanceCycle() { | |
208 | return ScoreboardHazardRecognizer::AdvanceCycle(); | |
209 | } | |
210 | ||
211 | void PPCDispatchGroupSBHazardRecognizer::RecedeCycle() { | |
212 | llvm_unreachable("Bottom-up scheduling not supported"); | |
213 | } | |
214 | ||
215 | void PPCDispatchGroupSBHazardRecognizer::Reset() { | |
216 | CurGroup.clear(); | |
217 | CurSlots = CurBranches = 0; | |
218 | return ScoreboardHazardRecognizer::Reset(); | |
219 | } | |
220 | ||
221 | void PPCDispatchGroupSBHazardRecognizer::EmitNoop() { | |
222 | unsigned Directive = | |
223 | DAG->TM.getSubtarget<PPCSubtarget>().getDarwinDirective(); | |
224 | // If the group has now filled all of its slots, or if we're using a special | |
225 | // group-terminating nop, the group is complete. | |
226 | if (Directive == PPC::DIR_PWR6 || Directive == PPC::DIR_PWR7 || | |
227 | Directive == PPC::DIR_PWR8 || CurSlots == 6) { | |
228 | CurGroup.clear(); | |
229 | CurSlots = CurBranches = 0; | |
230 | } else { | |
231 | CurGroup.push_back(nullptr); | |
232 | ++CurSlots; | |
233 | } | |
223e47cc LB |
234 | } |
235 | ||
236 | //===----------------------------------------------------------------------===// | |
237 | // PowerPC 970 Hazard Recognizer | |
238 | // | |
239 | // This models the dispatch group formation of the PPC970 processor. Dispatch | |
240 | // groups are bundles of up to five instructions that can contain various mixes | |
241 | // of instructions. The PPC970 can dispatch a peak of 4 non-branch and one | |
242 | // branch instruction per-cycle. | |
243 | // | |
244 | // There are a number of restrictions to dispatch group formation: some | |
245 | // instructions can only be issued in the first slot of a dispatch group, & some | |
246 | // instructions fill an entire dispatch group. Additionally, only branches can | |
247 | // issue in the 5th (last) slot. | |
248 | // | |
249 | // Finally, there are a number of "structural" hazards on the PPC970. These | |
250 | // conditions cause large performance penalties due to misprediction, recovery, | |
251 | // and replay logic that has to happen. These cases include setting a CTR and | |
252 | // branching through it in the same dispatch group, and storing to an address, | |
253 | // then loading from the same address within a dispatch group. To avoid these | |
254 | // conditions, we insert no-op instructions when appropriate. | |
255 | // | |
256 | // FIXME: This is missing some significant cases: | |
257 | // 1. Modeling of microcoded instructions. | |
258 | // 2. Handling of serialized operations. | |
259 | // 3. Handling of the esoteric cases in "Resource-based Instruction Grouping". | |
260 | // | |
261 | ||
1a4d82fc JJ |
262 | PPCHazardRecognizer970::PPCHazardRecognizer970(const ScheduleDAG &DAG) |
263 | : DAG(DAG) { | |
223e47cc LB |
264 | EndDispatchGroup(); |
265 | } | |
266 | ||
267 | void PPCHazardRecognizer970::EndDispatchGroup() { | |
268 | DEBUG(errs() << "=== Start of dispatch group\n"); | |
269 | NumIssued = 0; | |
270 | ||
271 | // Structural hazard info. | |
272 | HasCTRSet = false; | |
273 | NumStores = 0; | |
274 | } | |
275 | ||
276 | ||
277 | PPCII::PPC970_Unit | |
278 | PPCHazardRecognizer970::GetInstrType(unsigned Opcode, | |
279 | bool &isFirst, bool &isSingle, | |
280 | bool &isCracked, | |
281 | bool &isLoad, bool &isStore) { | |
1a4d82fc | 282 | const MCInstrDesc &MCID = DAG.TII->get(Opcode); |
223e47cc LB |
283 | |
284 | isLoad = MCID.mayLoad(); | |
285 | isStore = MCID.mayStore(); | |
286 | ||
287 | uint64_t TSFlags = MCID.TSFlags; | |
288 | ||
289 | isFirst = TSFlags & PPCII::PPC970_First; | |
290 | isSingle = TSFlags & PPCII::PPC970_Single; | |
291 | isCracked = TSFlags & PPCII::PPC970_Cracked; | |
292 | return (PPCII::PPC970_Unit)(TSFlags & PPCII::PPC970_Mask); | |
293 | } | |
294 | ||
295 | /// isLoadOfStoredAddress - If we have a load from the previously stored pointer | |
296 | /// as indicated by StorePtr1/StorePtr2/StoreSize, return true. | |
297 | bool PPCHazardRecognizer970:: | |
298 | isLoadOfStoredAddress(uint64_t LoadSize, int64_t LoadOffset, | |
299 | const Value *LoadValue) const { | |
300 | for (unsigned i = 0, e = NumStores; i != e; ++i) { | |
301 | // Handle exact and commuted addresses. | |
302 | if (LoadValue == StoreValue[i] && LoadOffset == StoreOffset[i]) | |
303 | return true; | |
304 | ||
305 | // Okay, we don't have an exact match, if this is an indexed offset, see if | |
306 | // we have overlap (which happens during fp->int conversion for example). | |
307 | if (StoreValue[i] == LoadValue) { | |
308 | // Okay the base pointers match, so we have [c1+r] vs [c2+r]. Check | |
309 | // to see if the load and store actually overlap. | |
310 | if (StoreOffset[i] < LoadOffset) { | |
311 | if (int64_t(StoreOffset[i]+StoreSize[i]) > LoadOffset) return true; | |
312 | } else { | |
313 | if (int64_t(LoadOffset+LoadSize) > StoreOffset[i]) return true; | |
314 | } | |
315 | } | |
316 | } | |
317 | return false; | |
318 | } | |
319 | ||
320 | /// getHazardType - We return hazard for any non-branch instruction that would | |
321 | /// terminate the dispatch group. We turn NoopHazard for any | |
322 | /// instructions that wouldn't terminate the dispatch group that would cause a | |
323 | /// pipeline flush. | |
324 | ScheduleHazardRecognizer::HazardType PPCHazardRecognizer970:: | |
325 | getHazardType(SUnit *SU, int Stalls) { | |
326 | assert(Stalls == 0 && "PPC hazards don't support scoreboard lookahead"); | |
327 | ||
328 | MachineInstr *MI = SU->getInstr(); | |
329 | ||
330 | if (MI->isDebugValue()) | |
331 | return NoHazard; | |
332 | ||
333 | unsigned Opcode = MI->getOpcode(); | |
334 | bool isFirst, isSingle, isCracked, isLoad, isStore; | |
335 | PPCII::PPC970_Unit InstrType = | |
336 | GetInstrType(Opcode, isFirst, isSingle, isCracked, | |
337 | isLoad, isStore); | |
338 | if (InstrType == PPCII::PPC970_Pseudo) return NoHazard; | |
339 | ||
340 | // We can only issue a PPC970_First/PPC970_Single instruction (such as | |
341 | // crand/mtspr/etc) if this is the first cycle of the dispatch group. | |
342 | if (NumIssued != 0 && (isFirst || isSingle)) | |
343 | return Hazard; | |
344 | ||
345 | // If this instruction is cracked into two ops by the decoder, we know that | |
346 | // it is not a branch and that it cannot issue if 3 other instructions are | |
347 | // already in the dispatch group. | |
348 | if (isCracked && NumIssued > 2) | |
349 | return Hazard; | |
350 | ||
351 | switch (InstrType) { | |
352 | default: llvm_unreachable("Unknown instruction type!"); | |
353 | case PPCII::PPC970_FXU: | |
354 | case PPCII::PPC970_LSU: | |
355 | case PPCII::PPC970_FPU: | |
356 | case PPCII::PPC970_VALU: | |
357 | case PPCII::PPC970_VPERM: | |
358 | // We can only issue a branch as the last instruction in a group. | |
359 | if (NumIssued == 4) return Hazard; | |
360 | break; | |
361 | case PPCII::PPC970_CRU: | |
362 | // We can only issue a CR instruction in the first two slots. | |
363 | if (NumIssued >= 2) return Hazard; | |
364 | break; | |
365 | case PPCII::PPC970_BRU: | |
366 | break; | |
367 | } | |
368 | ||
369 | // Do not allow MTCTR and BCTRL to be in the same dispatch group. | |
1a4d82fc | 370 | if (HasCTRSet && Opcode == PPC::BCTRL) |
223e47cc LB |
371 | return NoopHazard; |
372 | ||
373 | // If this is a load following a store, make sure it's not to the same or | |
374 | // overlapping address. | |
375 | if (isLoad && NumStores && !MI->memoperands_empty()) { | |
376 | MachineMemOperand *MO = *MI->memoperands_begin(); | |
377 | if (isLoadOfStoredAddress(MO->getSize(), | |
378 | MO->getOffset(), MO->getValue())) | |
379 | return NoopHazard; | |
380 | } | |
381 | ||
382 | return NoHazard; | |
383 | } | |
384 | ||
385 | void PPCHazardRecognizer970::EmitInstruction(SUnit *SU) { | |
386 | MachineInstr *MI = SU->getInstr(); | |
387 | ||
388 | if (MI->isDebugValue()) | |
389 | return; | |
390 | ||
391 | unsigned Opcode = MI->getOpcode(); | |
392 | bool isFirst, isSingle, isCracked, isLoad, isStore; | |
393 | PPCII::PPC970_Unit InstrType = | |
394 | GetInstrType(Opcode, isFirst, isSingle, isCracked, | |
395 | isLoad, isStore); | |
396 | if (InstrType == PPCII::PPC970_Pseudo) return; | |
397 | ||
398 | // Update structural hazard information. | |
399 | if (Opcode == PPC::MTCTR || Opcode == PPC::MTCTR8) HasCTRSet = true; | |
400 | ||
401 | // Track the address stored to. | |
402 | if (isStore && NumStores < 4 && !MI->memoperands_empty()) { | |
403 | MachineMemOperand *MO = *MI->memoperands_begin(); | |
404 | StoreSize[NumStores] = MO->getSize(); | |
405 | StoreOffset[NumStores] = MO->getOffset(); | |
406 | StoreValue[NumStores] = MO->getValue(); | |
407 | ++NumStores; | |
408 | } | |
409 | ||
410 | if (InstrType == PPCII::PPC970_BRU || isSingle) | |
411 | NumIssued = 4; // Terminate a d-group. | |
412 | ++NumIssued; | |
413 | ||
414 | // If this instruction is cracked into two ops by the decoder, remember that | |
415 | // we issued two pieces. | |
416 | if (isCracked) | |
417 | ++NumIssued; | |
418 | ||
419 | if (NumIssued == 5) | |
420 | EndDispatchGroup(); | |
421 | } | |
422 | ||
423 | void PPCHazardRecognizer970::AdvanceCycle() { | |
424 | assert(NumIssued < 5 && "Illegal dispatch group!"); | |
425 | ++NumIssued; | |
426 | if (NumIssued == 5) | |
427 | EndDispatchGroup(); | |
428 | } | |
429 | ||
430 | void PPCHazardRecognizer970::Reset() { | |
431 | EndDispatchGroup(); | |
432 | } | |
433 |