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