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