10b57cec5SDimitry Andric //===-- PPCHazardRecognizers.cpp - PowerPC Hazard Recognizer Impls --------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file implements hazard recognizers for scheduling on PowerPC processors.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #include "PPCHazardRecognizers.h"
140b57cec5SDimitry Andric #include "PPCInstrInfo.h"
150b57cec5SDimitry Andric #include "PPCSubtarget.h"
160b57cec5SDimitry Andric #include "llvm/CodeGen/ScheduleDAG.h"
170b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
180b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
190b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
200b57cec5SDimitry Andric using namespace llvm;
210b57cec5SDimitry Andric 
220b57cec5SDimitry Andric #define DEBUG_TYPE "pre-RA-sched"
230b57cec5SDimitry Andric 
isLoadAfterStore(SUnit * SU)240b57cec5SDimitry Andric bool PPCDispatchGroupSBHazardRecognizer::isLoadAfterStore(SUnit *SU) {
250b57cec5SDimitry Andric   // FIXME: Move this.
260b57cec5SDimitry Andric   if (isBCTRAfterSet(SU))
270b57cec5SDimitry Andric     return true;
280b57cec5SDimitry Andric 
290b57cec5SDimitry Andric   const MCInstrDesc *MCID = DAG->getInstrDesc(SU);
300b57cec5SDimitry Andric   if (!MCID)
310b57cec5SDimitry Andric     return false;
320b57cec5SDimitry Andric 
330b57cec5SDimitry Andric   if (!MCID->mayLoad())
340b57cec5SDimitry Andric     return false;
350b57cec5SDimitry Andric 
360b57cec5SDimitry Andric   // SU is a load; for any predecessors in this dispatch group, that are stores,
370b57cec5SDimitry Andric   // and with which we have an ordering dependency, return true.
380b57cec5SDimitry Andric   for (unsigned i = 0, ie = (unsigned) SU->Preds.size(); i != ie; ++i) {
390b57cec5SDimitry Andric     const MCInstrDesc *PredMCID = DAG->getInstrDesc(SU->Preds[i].getSUnit());
400b57cec5SDimitry Andric     if (!PredMCID || !PredMCID->mayStore())
410b57cec5SDimitry Andric       continue;
420b57cec5SDimitry Andric 
430b57cec5SDimitry Andric     if (!SU->Preds[i].isNormalMemory() && !SU->Preds[i].isBarrier())
440b57cec5SDimitry Andric       continue;
450b57cec5SDimitry Andric 
460b57cec5SDimitry Andric     for (unsigned j = 0, je = CurGroup.size(); j != je; ++j)
470b57cec5SDimitry Andric       if (SU->Preds[i].getSUnit() == CurGroup[j])
480b57cec5SDimitry Andric         return true;
490b57cec5SDimitry Andric   }
500b57cec5SDimitry Andric 
510b57cec5SDimitry Andric   return false;
520b57cec5SDimitry Andric }
530b57cec5SDimitry Andric 
isBCTRAfterSet(SUnit * SU)540b57cec5SDimitry Andric bool PPCDispatchGroupSBHazardRecognizer::isBCTRAfterSet(SUnit *SU) {
550b57cec5SDimitry Andric   const MCInstrDesc *MCID = DAG->getInstrDesc(SU);
560b57cec5SDimitry Andric   if (!MCID)
570b57cec5SDimitry Andric     return false;
580b57cec5SDimitry Andric 
590b57cec5SDimitry Andric   if (!MCID->isBranch())
600b57cec5SDimitry Andric     return false;
610b57cec5SDimitry Andric 
620b57cec5SDimitry Andric   // SU is a branch; for any predecessors in this dispatch group, with which we
630b57cec5SDimitry Andric   // have a data dependence and set the counter register, return true.
640b57cec5SDimitry Andric   for (unsigned i = 0, ie = (unsigned) SU->Preds.size(); i != ie; ++i) {
650b57cec5SDimitry Andric     const MCInstrDesc *PredMCID = DAG->getInstrDesc(SU->Preds[i].getSUnit());
660b57cec5SDimitry Andric     if (!PredMCID || PredMCID->getSchedClass() != PPC::Sched::IIC_SprMTSPR)
670b57cec5SDimitry Andric       continue;
680b57cec5SDimitry Andric 
690b57cec5SDimitry Andric     if (SU->Preds[i].isCtrl())
700b57cec5SDimitry Andric       continue;
710b57cec5SDimitry Andric 
720b57cec5SDimitry Andric     for (unsigned j = 0, je = CurGroup.size(); j != je; ++j)
730b57cec5SDimitry Andric       if (SU->Preds[i].getSUnit() == CurGroup[j])
740b57cec5SDimitry Andric         return true;
750b57cec5SDimitry Andric   }
760b57cec5SDimitry Andric 
770b57cec5SDimitry Andric   return false;
780b57cec5SDimitry Andric }
790b57cec5SDimitry Andric 
800b57cec5SDimitry Andric // FIXME: Remove this when we don't need this:
810b57cec5SDimitry Andric namespace llvm { namespace PPC { extern int getNonRecordFormOpcode(uint16_t); } }
820b57cec5SDimitry Andric 
830b57cec5SDimitry Andric // FIXME: A lot of code in PPCDispatchGroupSBHazardRecognizer is P7 specific.
840b57cec5SDimitry Andric 
mustComeFirst(const MCInstrDesc * MCID,unsigned & NSlots)850b57cec5SDimitry Andric bool PPCDispatchGroupSBHazardRecognizer::mustComeFirst(const MCInstrDesc *MCID,
860b57cec5SDimitry Andric                                                        unsigned &NSlots) {
870b57cec5SDimitry Andric   // FIXME: Indirectly, this information is contained in the itinerary, and
880b57cec5SDimitry Andric   // we should derive it from there instead of separately specifying it
890b57cec5SDimitry Andric   // here.
900b57cec5SDimitry Andric   unsigned IIC = MCID->getSchedClass();
910b57cec5SDimitry Andric   switch (IIC) {
920b57cec5SDimitry Andric   default:
930b57cec5SDimitry Andric     NSlots = 1;
940b57cec5SDimitry Andric     break;
950b57cec5SDimitry Andric   case PPC::Sched::IIC_IntDivW:
960b57cec5SDimitry Andric   case PPC::Sched::IIC_IntDivD:
970b57cec5SDimitry Andric   case PPC::Sched::IIC_LdStLoadUpd:
980b57cec5SDimitry Andric   case PPC::Sched::IIC_LdStLDU:
990b57cec5SDimitry Andric   case PPC::Sched::IIC_LdStLFDU:
1000b57cec5SDimitry Andric   case PPC::Sched::IIC_LdStLFDUX:
1010b57cec5SDimitry Andric   case PPC::Sched::IIC_LdStLHA:
1020b57cec5SDimitry Andric   case PPC::Sched::IIC_LdStLHAU:
1030b57cec5SDimitry Andric   case PPC::Sched::IIC_LdStLWA:
1040b57cec5SDimitry Andric   case PPC::Sched::IIC_LdStSTU:
1050b57cec5SDimitry Andric   case PPC::Sched::IIC_LdStSTFDU:
1060b57cec5SDimitry Andric     NSlots = 2;
1070b57cec5SDimitry Andric     break;
1080b57cec5SDimitry Andric   case PPC::Sched::IIC_LdStLoadUpdX:
1090b57cec5SDimitry Andric   case PPC::Sched::IIC_LdStLDUX:
1100b57cec5SDimitry Andric   case PPC::Sched::IIC_LdStLHAUX:
1110b57cec5SDimitry Andric   case PPC::Sched::IIC_LdStLWARX:
1120b57cec5SDimitry Andric   case PPC::Sched::IIC_LdStLDARX:
1130b57cec5SDimitry Andric   case PPC::Sched::IIC_LdStSTUX:
1140b57cec5SDimitry Andric   case PPC::Sched::IIC_LdStSTDCX:
1150b57cec5SDimitry Andric   case PPC::Sched::IIC_LdStSTWCX:
1160b57cec5SDimitry Andric   case PPC::Sched::IIC_BrMCRX: // mtcr
1170b57cec5SDimitry Andric   // FIXME: Add sync/isync (here and in the itinerary).
1180b57cec5SDimitry Andric     NSlots = 4;
1190b57cec5SDimitry Andric     break;
1200b57cec5SDimitry Andric   }
1210b57cec5SDimitry Andric 
1220b57cec5SDimitry Andric   // FIXME: record-form instructions need a different itinerary class.
1230b57cec5SDimitry Andric   if (NSlots == 1 && PPC::getNonRecordFormOpcode(MCID->getOpcode()) != -1)
1240b57cec5SDimitry Andric     NSlots = 2;
1250b57cec5SDimitry Andric 
1260b57cec5SDimitry Andric   switch (IIC) {
1270b57cec5SDimitry Andric   default:
1280b57cec5SDimitry Andric     // All multi-slot instructions must come first.
1290b57cec5SDimitry Andric     return NSlots > 1;
1300b57cec5SDimitry Andric   case PPC::Sched::IIC_BrCR: // cr logicals
1310b57cec5SDimitry Andric   case PPC::Sched::IIC_SprMFCR:
1320b57cec5SDimitry Andric   case PPC::Sched::IIC_SprMFCRF:
1330b57cec5SDimitry Andric   case PPC::Sched::IIC_SprMTSPR:
1340b57cec5SDimitry Andric     return true;
1350b57cec5SDimitry Andric   }
1360b57cec5SDimitry Andric }
1370b57cec5SDimitry Andric 
1380b57cec5SDimitry Andric ScheduleHazardRecognizer::HazardType
getHazardType(SUnit * SU,int Stalls)1390b57cec5SDimitry Andric PPCDispatchGroupSBHazardRecognizer::getHazardType(SUnit *SU, int Stalls) {
1400b57cec5SDimitry Andric   if (Stalls == 0 && isLoadAfterStore(SU))
1410b57cec5SDimitry Andric     return NoopHazard;
1420b57cec5SDimitry Andric 
1430b57cec5SDimitry Andric   return ScoreboardHazardRecognizer::getHazardType(SU, Stalls);
1440b57cec5SDimitry Andric }
1450b57cec5SDimitry Andric 
ShouldPreferAnother(SUnit * SU)1460b57cec5SDimitry Andric bool PPCDispatchGroupSBHazardRecognizer::ShouldPreferAnother(SUnit *SU) {
1470b57cec5SDimitry Andric   const MCInstrDesc *MCID = DAG->getInstrDesc(SU);
1480b57cec5SDimitry Andric   unsigned NSlots;
1490b57cec5SDimitry Andric   if (MCID && mustComeFirst(MCID, NSlots) && CurSlots)
1500b57cec5SDimitry Andric     return true;
1510b57cec5SDimitry Andric 
1520b57cec5SDimitry Andric   return ScoreboardHazardRecognizer::ShouldPreferAnother(SU);
1530b57cec5SDimitry Andric }
1540b57cec5SDimitry Andric 
PreEmitNoops(SUnit * SU)1550b57cec5SDimitry Andric unsigned PPCDispatchGroupSBHazardRecognizer::PreEmitNoops(SUnit *SU) {
1560b57cec5SDimitry Andric   // We only need to fill out a maximum of 5 slots here: The 6th slot could
1570b57cec5SDimitry Andric   // only be a second branch, and otherwise the next instruction will start a
1580b57cec5SDimitry Andric   // new group.
1590b57cec5SDimitry Andric   if (isLoadAfterStore(SU) && CurSlots < 6) {
1600b57cec5SDimitry Andric     unsigned Directive =
1610b57cec5SDimitry Andric         DAG->MF.getSubtarget<PPCSubtarget>().getCPUDirective();
1620b57cec5SDimitry Andric     // If we're using a special group-terminating nop, then we need only one.
1630b57cec5SDimitry Andric     // FIXME: the same for P9 as previous gen until POWER9 scheduling is ready
1640b57cec5SDimitry Andric     if (Directive == PPC::DIR_PWR6 || Directive == PPC::DIR_PWR7 ||
1650b57cec5SDimitry Andric         Directive == PPC::DIR_PWR8 || Directive == PPC::DIR_PWR9)
1660b57cec5SDimitry Andric       return 1;
1670b57cec5SDimitry Andric 
1680b57cec5SDimitry Andric     return 5 - CurSlots;
1690b57cec5SDimitry Andric   }
1700b57cec5SDimitry Andric 
1710b57cec5SDimitry Andric   return ScoreboardHazardRecognizer::PreEmitNoops(SU);
1720b57cec5SDimitry Andric }
1730b57cec5SDimitry Andric 
EmitInstruction(SUnit * SU)1740b57cec5SDimitry Andric void PPCDispatchGroupSBHazardRecognizer::EmitInstruction(SUnit *SU) {
1750b57cec5SDimitry Andric   const MCInstrDesc *MCID = DAG->getInstrDesc(SU);
1760b57cec5SDimitry Andric   if (MCID) {
1770b57cec5SDimitry Andric     if (CurSlots == 5 || (MCID->isBranch() && CurBranches == 1)) {
1780b57cec5SDimitry Andric       CurGroup.clear();
1790b57cec5SDimitry Andric       CurSlots = CurBranches = 0;
1800b57cec5SDimitry Andric     } else {
1810b57cec5SDimitry Andric       LLVM_DEBUG(dbgs() << "**** Adding to dispatch group: ");
1820b57cec5SDimitry Andric       LLVM_DEBUG(DAG->dumpNode(*SU));
1830b57cec5SDimitry Andric 
1840b57cec5SDimitry Andric       unsigned NSlots;
1850b57cec5SDimitry Andric       bool MustBeFirst = mustComeFirst(MCID, NSlots);
1860b57cec5SDimitry Andric 
1870b57cec5SDimitry Andric       // If this instruction must come first, but does not, then it starts a
1880b57cec5SDimitry Andric       // new group.
1890b57cec5SDimitry Andric       if (MustBeFirst && CurSlots) {
1900b57cec5SDimitry Andric         CurSlots = CurBranches = 0;
1910b57cec5SDimitry Andric         CurGroup.clear();
1920b57cec5SDimitry Andric       }
1930b57cec5SDimitry Andric 
1940b57cec5SDimitry Andric       CurSlots += NSlots;
1950b57cec5SDimitry Andric       CurGroup.push_back(SU);
1960b57cec5SDimitry Andric 
1970b57cec5SDimitry Andric       if (MCID->isBranch())
1980b57cec5SDimitry Andric         ++CurBranches;
1990b57cec5SDimitry Andric     }
2000b57cec5SDimitry Andric   }
2010b57cec5SDimitry Andric 
2020b57cec5SDimitry Andric   return ScoreboardHazardRecognizer::EmitInstruction(SU);
2030b57cec5SDimitry Andric }
2040b57cec5SDimitry Andric 
AdvanceCycle()2050b57cec5SDimitry Andric void PPCDispatchGroupSBHazardRecognizer::AdvanceCycle() {
2060b57cec5SDimitry Andric   return ScoreboardHazardRecognizer::AdvanceCycle();
2070b57cec5SDimitry Andric }
2080b57cec5SDimitry Andric 
RecedeCycle()2090b57cec5SDimitry Andric void PPCDispatchGroupSBHazardRecognizer::RecedeCycle() {
2100b57cec5SDimitry Andric   llvm_unreachable("Bottom-up scheduling not supported");
2110b57cec5SDimitry Andric }
2120b57cec5SDimitry Andric 
Reset()2130b57cec5SDimitry Andric void PPCDispatchGroupSBHazardRecognizer::Reset() {
2140b57cec5SDimitry Andric   CurGroup.clear();
2150b57cec5SDimitry Andric   CurSlots = CurBranches = 0;
2160b57cec5SDimitry Andric   return ScoreboardHazardRecognizer::Reset();
2170b57cec5SDimitry Andric }
2180b57cec5SDimitry Andric 
EmitNoop()2190b57cec5SDimitry Andric void PPCDispatchGroupSBHazardRecognizer::EmitNoop() {
2200b57cec5SDimitry Andric   unsigned Directive =
2210b57cec5SDimitry Andric       DAG->MF.getSubtarget<PPCSubtarget>().getCPUDirective();
2220b57cec5SDimitry Andric   // If the group has now filled all of its slots, or if we're using a special
2230b57cec5SDimitry Andric   // group-terminating nop, the group is complete.
2240b57cec5SDimitry Andric   // FIXME: the same for P9 as previous gen until POWER9 scheduling is ready
2250b57cec5SDimitry Andric   if (Directive == PPC::DIR_PWR6 || Directive == PPC::DIR_PWR7 ||
2260b57cec5SDimitry Andric       Directive == PPC::DIR_PWR8 || Directive == PPC::DIR_PWR9 ||
2270b57cec5SDimitry Andric       CurSlots == 6) {
2280b57cec5SDimitry Andric     CurGroup.clear();
2290b57cec5SDimitry Andric     CurSlots = CurBranches = 0;
2300b57cec5SDimitry Andric   } else {
2310b57cec5SDimitry Andric     CurGroup.push_back(nullptr);
2320b57cec5SDimitry Andric     ++CurSlots;
2330b57cec5SDimitry Andric   }
2340b57cec5SDimitry Andric }
2350b57cec5SDimitry Andric 
2360b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
2370b57cec5SDimitry Andric // PowerPC 970 Hazard Recognizer
2380b57cec5SDimitry Andric //
2390b57cec5SDimitry Andric // This models the dispatch group formation of the PPC970 processor.  Dispatch
2400b57cec5SDimitry Andric // groups are bundles of up to five instructions that can contain various mixes
2410b57cec5SDimitry Andric // of instructions.  The PPC970 can dispatch a peak of 4 non-branch and one
2420b57cec5SDimitry Andric // branch instruction per-cycle.
2430b57cec5SDimitry Andric //
2440b57cec5SDimitry Andric // There are a number of restrictions to dispatch group formation: some
2450b57cec5SDimitry Andric // instructions can only be issued in the first slot of a dispatch group, & some
2460b57cec5SDimitry Andric // instructions fill an entire dispatch group.  Additionally, only branches can
2470b57cec5SDimitry Andric // issue in the 5th (last) slot.
2480b57cec5SDimitry Andric //
2490b57cec5SDimitry Andric // Finally, there are a number of "structural" hazards on the PPC970.  These
2500b57cec5SDimitry Andric // conditions cause large performance penalties due to misprediction, recovery,
2510b57cec5SDimitry Andric // and replay logic that has to happen.  These cases include setting a CTR and
2520b57cec5SDimitry Andric // branching through it in the same dispatch group, and storing to an address,
2530b57cec5SDimitry Andric // then loading from the same address within a dispatch group.  To avoid these
2540b57cec5SDimitry Andric // conditions, we insert no-op instructions when appropriate.
2550b57cec5SDimitry Andric //
2560b57cec5SDimitry Andric // FIXME: This is missing some significant cases:
2570b57cec5SDimitry Andric //   1. Modeling of microcoded instructions.
2580b57cec5SDimitry Andric //   2. Handling of serialized operations.
2590b57cec5SDimitry Andric //   3. Handling of the esoteric cases in "Resource-based Instruction Grouping".
2600b57cec5SDimitry Andric //
2610b57cec5SDimitry Andric 
PPCHazardRecognizer970(const ScheduleDAG & DAG)2620b57cec5SDimitry Andric PPCHazardRecognizer970::PPCHazardRecognizer970(const ScheduleDAG &DAG)
2630b57cec5SDimitry Andric     : DAG(DAG) {
2640b57cec5SDimitry Andric   EndDispatchGroup();
2650b57cec5SDimitry Andric }
2660b57cec5SDimitry Andric 
EndDispatchGroup()2670b57cec5SDimitry Andric void PPCHazardRecognizer970::EndDispatchGroup() {
2680b57cec5SDimitry Andric   LLVM_DEBUG(errs() << "=== Start of dispatch group\n");
2690b57cec5SDimitry Andric   NumIssued = 0;
2700b57cec5SDimitry Andric 
2710b57cec5SDimitry Andric   // Structural hazard info.
2720b57cec5SDimitry Andric   HasCTRSet = false;
2730b57cec5SDimitry Andric   NumStores = 0;
2740b57cec5SDimitry Andric }
2750b57cec5SDimitry Andric 
2760b57cec5SDimitry Andric 
2770b57cec5SDimitry Andric PPCII::PPC970_Unit
GetInstrType(unsigned Opcode,bool & isFirst,bool & isSingle,bool & isCracked,bool & isLoad,bool & isStore)2780b57cec5SDimitry Andric PPCHazardRecognizer970::GetInstrType(unsigned Opcode,
2790b57cec5SDimitry Andric                                      bool &isFirst, bool &isSingle,
2800b57cec5SDimitry Andric                                      bool &isCracked,
2810b57cec5SDimitry Andric                                      bool &isLoad, bool &isStore) {
2820b57cec5SDimitry Andric   const MCInstrDesc &MCID = DAG.TII->get(Opcode);
2830b57cec5SDimitry Andric 
2840b57cec5SDimitry Andric   isLoad  = MCID.mayLoad();
2850b57cec5SDimitry Andric   isStore = MCID.mayStore();
2860b57cec5SDimitry Andric 
2870b57cec5SDimitry Andric   uint64_t TSFlags = MCID.TSFlags;
2880b57cec5SDimitry Andric 
2890b57cec5SDimitry Andric   isFirst   = TSFlags & PPCII::PPC970_First;
2900b57cec5SDimitry Andric   isSingle  = TSFlags & PPCII::PPC970_Single;
2910b57cec5SDimitry Andric   isCracked = TSFlags & PPCII::PPC970_Cracked;
2920b57cec5SDimitry Andric   return (PPCII::PPC970_Unit)(TSFlags & PPCII::PPC970_Mask);
2930b57cec5SDimitry Andric }
2940b57cec5SDimitry Andric 
2950b57cec5SDimitry Andric /// isLoadOfStoredAddress - If we have a load from the previously stored pointer
2960b57cec5SDimitry Andric /// as indicated by StorePtr1/StorePtr2/StoreSize, return true.
2970b57cec5SDimitry Andric bool PPCHazardRecognizer970::
isLoadOfStoredAddress(uint64_t LoadSize,int64_t LoadOffset,const Value * LoadValue) const2980b57cec5SDimitry Andric isLoadOfStoredAddress(uint64_t LoadSize, int64_t LoadOffset,
2990b57cec5SDimitry Andric   const Value *LoadValue) const {
3000b57cec5SDimitry Andric   for (unsigned i = 0, e = NumStores; i != e; ++i) {
3010b57cec5SDimitry Andric     // Handle exact and commuted addresses.
3020b57cec5SDimitry Andric     if (LoadValue == StoreValue[i] && LoadOffset == StoreOffset[i])
3030b57cec5SDimitry Andric       return true;
3040b57cec5SDimitry Andric 
3050b57cec5SDimitry Andric     // Okay, we don't have an exact match, if this is an indexed offset, see if
3060b57cec5SDimitry Andric     // we have overlap (which happens during fp->int conversion for example).
3070b57cec5SDimitry Andric     if (StoreValue[i] == LoadValue) {
3080b57cec5SDimitry Andric       // Okay the base pointers match, so we have [c1+r] vs [c2+r].  Check
3090b57cec5SDimitry Andric       // to see if the load and store actually overlap.
3100b57cec5SDimitry Andric       if (StoreOffset[i] < LoadOffset) {
3110b57cec5SDimitry Andric         if (int64_t(StoreOffset[i]+StoreSize[i]) > LoadOffset) return true;
3120b57cec5SDimitry Andric       } else {
3130b57cec5SDimitry Andric         if (int64_t(LoadOffset+LoadSize) > StoreOffset[i]) return true;
3140b57cec5SDimitry Andric       }
3150b57cec5SDimitry Andric     }
3160b57cec5SDimitry Andric   }
3170b57cec5SDimitry Andric   return false;
3180b57cec5SDimitry Andric }
3190b57cec5SDimitry Andric 
3200b57cec5SDimitry Andric /// getHazardType - We return hazard for any non-branch instruction that would
3210b57cec5SDimitry Andric /// terminate the dispatch group.  We turn NoopHazard for any
3220b57cec5SDimitry Andric /// instructions that wouldn't terminate the dispatch group that would cause a
3230b57cec5SDimitry Andric /// pipeline flush.
3240b57cec5SDimitry Andric ScheduleHazardRecognizer::HazardType PPCHazardRecognizer970::
getHazardType(SUnit * SU,int Stalls)3250b57cec5SDimitry Andric getHazardType(SUnit *SU, int Stalls) {
3260b57cec5SDimitry Andric   assert(Stalls == 0 && "PPC hazards don't support scoreboard lookahead");
3270b57cec5SDimitry Andric 
3280b57cec5SDimitry Andric   MachineInstr *MI = SU->getInstr();
3290b57cec5SDimitry Andric 
3300b57cec5SDimitry Andric   if (MI->isDebugInstr())
3310b57cec5SDimitry Andric     return NoHazard;
3320b57cec5SDimitry Andric 
3330b57cec5SDimitry Andric   unsigned Opcode = MI->getOpcode();
3340b57cec5SDimitry Andric   bool isFirst, isSingle, isCracked, isLoad, isStore;
3350b57cec5SDimitry Andric   PPCII::PPC970_Unit InstrType =
3360b57cec5SDimitry Andric     GetInstrType(Opcode, isFirst, isSingle, isCracked,
3370b57cec5SDimitry Andric                  isLoad, isStore);
3380b57cec5SDimitry Andric   if (InstrType == PPCII::PPC970_Pseudo) return NoHazard;
3390b57cec5SDimitry Andric 
3400b57cec5SDimitry Andric   // We can only issue a PPC970_First/PPC970_Single instruction (such as
3410b57cec5SDimitry Andric   // crand/mtspr/etc) if this is the first cycle of the dispatch group.
3420b57cec5SDimitry Andric   if (NumIssued != 0 && (isFirst || isSingle))
3430b57cec5SDimitry Andric     return Hazard;
3440b57cec5SDimitry Andric 
3450b57cec5SDimitry Andric   // If this instruction is cracked into two ops by the decoder, we know that
3460b57cec5SDimitry Andric   // it is not a branch and that it cannot issue if 3 other instructions are
3470b57cec5SDimitry Andric   // already in the dispatch group.
3480b57cec5SDimitry Andric   if (isCracked && NumIssued > 2)
3490b57cec5SDimitry Andric     return Hazard;
3500b57cec5SDimitry Andric 
3510b57cec5SDimitry Andric   switch (InstrType) {
3520b57cec5SDimitry Andric   default: llvm_unreachable("Unknown instruction type!");
3530b57cec5SDimitry Andric   case PPCII::PPC970_FXU:
3540b57cec5SDimitry Andric   case PPCII::PPC970_LSU:
3550b57cec5SDimitry Andric   case PPCII::PPC970_FPU:
3560b57cec5SDimitry Andric   case PPCII::PPC970_VALU:
3570b57cec5SDimitry Andric   case PPCII::PPC970_VPERM:
3580b57cec5SDimitry Andric     // We can only issue a branch as the last instruction in a group.
3590b57cec5SDimitry Andric     if (NumIssued == 4) return Hazard;
3600b57cec5SDimitry Andric     break;
3610b57cec5SDimitry Andric   case PPCII::PPC970_CRU:
3620b57cec5SDimitry Andric     // We can only issue a CR instruction in the first two slots.
3630b57cec5SDimitry Andric     if (NumIssued >= 2) return Hazard;
3640b57cec5SDimitry Andric     break;
3650b57cec5SDimitry Andric   case PPCII::PPC970_BRU:
3660b57cec5SDimitry Andric     break;
3670b57cec5SDimitry Andric   }
3680b57cec5SDimitry Andric 
3690b57cec5SDimitry Andric   // Do not allow MTCTR and BCTRL to be in the same dispatch group.
3700b57cec5SDimitry Andric   if (HasCTRSet && Opcode == PPC::BCTRL)
3710b57cec5SDimitry Andric     return NoopHazard;
3720b57cec5SDimitry Andric 
3730b57cec5SDimitry Andric   // If this is a load following a store, make sure it's not to the same or
3740b57cec5SDimitry Andric   // overlapping address.
3750b57cec5SDimitry Andric   if (isLoad && NumStores && !MI->memoperands_empty()) {
3760b57cec5SDimitry Andric     MachineMemOperand *MO = *MI->memoperands_begin();
3770b57cec5SDimitry Andric     if (isLoadOfStoredAddress(MO->getSize(),
3780b57cec5SDimitry Andric                               MO->getOffset(), MO->getValue()))
3790b57cec5SDimitry Andric       return NoopHazard;
3800b57cec5SDimitry Andric   }
3810b57cec5SDimitry Andric 
3820b57cec5SDimitry Andric   return NoHazard;
3830b57cec5SDimitry Andric }
3840b57cec5SDimitry Andric 
EmitInstruction(SUnit * SU)3850b57cec5SDimitry Andric void PPCHazardRecognizer970::EmitInstruction(SUnit *SU) {
3860b57cec5SDimitry Andric   MachineInstr *MI = SU->getInstr();
3870b57cec5SDimitry Andric 
3880b57cec5SDimitry Andric   if (MI->isDebugInstr())
3890b57cec5SDimitry Andric     return;
3900b57cec5SDimitry Andric 
3910b57cec5SDimitry Andric   unsigned Opcode = MI->getOpcode();
3920b57cec5SDimitry Andric   bool isFirst, isSingle, isCracked, isLoad, isStore;
3930b57cec5SDimitry Andric   PPCII::PPC970_Unit InstrType =
3940b57cec5SDimitry Andric     GetInstrType(Opcode, isFirst, isSingle, isCracked,
3950b57cec5SDimitry Andric                  isLoad, isStore);
3960b57cec5SDimitry Andric   if (InstrType == PPCII::PPC970_Pseudo) return;
3970b57cec5SDimitry Andric 
3980b57cec5SDimitry Andric   // Update structural hazard information.
3990b57cec5SDimitry Andric   if (Opcode == PPC::MTCTR || Opcode == PPC::MTCTR8) HasCTRSet = true;
4000b57cec5SDimitry Andric 
4010b57cec5SDimitry Andric   // Track the address stored to.
4020b57cec5SDimitry Andric   if (isStore && NumStores < 4 && !MI->memoperands_empty()) {
4030b57cec5SDimitry Andric     MachineMemOperand *MO = *MI->memoperands_begin();
4040b57cec5SDimitry Andric     StoreSize[NumStores] = MO->getSize();
4050b57cec5SDimitry Andric     StoreOffset[NumStores] = MO->getOffset();
4060b57cec5SDimitry Andric     StoreValue[NumStores] = MO->getValue();
4070b57cec5SDimitry Andric     ++NumStores;
4080b57cec5SDimitry Andric   }
4090b57cec5SDimitry Andric 
4100b57cec5SDimitry Andric   if (InstrType == PPCII::PPC970_BRU || isSingle)
4110b57cec5SDimitry Andric     NumIssued = 4;  // Terminate a d-group.
4120b57cec5SDimitry Andric   ++NumIssued;
4130b57cec5SDimitry Andric 
4140b57cec5SDimitry Andric   // If this instruction is cracked into two ops by the decoder, remember that
4150b57cec5SDimitry Andric   // we issued two pieces.
4160b57cec5SDimitry Andric   if (isCracked)
4170b57cec5SDimitry Andric     ++NumIssued;
4180b57cec5SDimitry Andric 
4190b57cec5SDimitry Andric   if (NumIssued == 5)
4200b57cec5SDimitry Andric     EndDispatchGroup();
4210b57cec5SDimitry Andric }
4220b57cec5SDimitry Andric 
AdvanceCycle()4230b57cec5SDimitry Andric void PPCHazardRecognizer970::AdvanceCycle() {
4240b57cec5SDimitry Andric   assert(NumIssued < 5 && "Illegal dispatch group!");
4250b57cec5SDimitry Andric   ++NumIssued;
4260b57cec5SDimitry Andric   if (NumIssued == 5)
4270b57cec5SDimitry Andric     EndDispatchGroup();
4280b57cec5SDimitry Andric }
4290b57cec5SDimitry Andric 
Reset()4300b57cec5SDimitry Andric void PPCHazardRecognizer970::Reset() {
4310b57cec5SDimitry Andric   EndDispatchGroup();
4320b57cec5SDimitry Andric }
4330b57cec5SDimitry Andric 
434