aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/llvm12/lib/Target/PowerPC/PPCHazardRecognizers.cpp
diff options
context:
space:
mode:
authororivej <orivej@yandex-team.ru>2022-02-10 16:45:01 +0300
committerDaniil Cherednik <dcherednik@yandex-team.ru>2022-02-10 16:45:01 +0300
commit2d37894b1b037cf24231090eda8589bbb44fb6fc (patch)
treebe835aa92c6248212e705f25388ebafcf84bc7a1 /contrib/libs/llvm12/lib/Target/PowerPC/PPCHazardRecognizers.cpp
parent718c552901d703c502ccbefdfc3c9028d608b947 (diff)
downloadydb-2d37894b1b037cf24231090eda8589bbb44fb6fc.tar.gz
Restoring authorship annotation for <orivej@yandex-team.ru>. Commit 2 of 2.
Diffstat (limited to 'contrib/libs/llvm12/lib/Target/PowerPC/PPCHazardRecognizers.cpp')
-rw-r--r--contrib/libs/llvm12/lib/Target/PowerPC/PPCHazardRecognizers.cpp866
1 files changed, 433 insertions, 433 deletions
diff --git a/contrib/libs/llvm12/lib/Target/PowerPC/PPCHazardRecognizers.cpp b/contrib/libs/llvm12/lib/Target/PowerPC/PPCHazardRecognizers.cpp
index f8dc331876..ffaa3e05c8 100644
--- a/contrib/libs/llvm12/lib/Target/PowerPC/PPCHazardRecognizers.cpp
+++ b/contrib/libs/llvm12/lib/Target/PowerPC/PPCHazardRecognizers.cpp
@@ -1,433 +1,433 @@
-//===-- PPCHazardRecognizers.cpp - PowerPC Hazard Recognizer Impls --------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This file implements hazard recognizers for scheduling on PowerPC processors.
-//
-//===----------------------------------------------------------------------===//
-
-#include "PPCHazardRecognizers.h"
-#include "PPCInstrInfo.h"
-#include "PPCSubtarget.h"
-#include "llvm/CodeGen/ScheduleDAG.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/raw_ostream.h"
-using namespace llvm;
-
-#define DEBUG_TYPE "pre-RA-sched"
-
-bool PPCDispatchGroupSBHazardRecognizer::isLoadAfterStore(SUnit *SU) {
- // FIXME: Move this.
- if (isBCTRAfterSet(SU))
- return true;
-
- const MCInstrDesc *MCID = DAG->getInstrDesc(SU);
- if (!MCID)
- return false;
-
- if (!MCID->mayLoad())
- return false;
-
- // SU is a load; for any predecessors in this dispatch group, that are stores,
- // and with which we have an ordering dependency, return true.
- for (unsigned i = 0, ie = (unsigned) SU->Preds.size(); i != ie; ++i) {
- const MCInstrDesc *PredMCID = DAG->getInstrDesc(SU->Preds[i].getSUnit());
- if (!PredMCID || !PredMCID->mayStore())
- continue;
-
- if (!SU->Preds[i].isNormalMemory() && !SU->Preds[i].isBarrier())
- continue;
-
- for (unsigned j = 0, je = CurGroup.size(); j != je; ++j)
- if (SU->Preds[i].getSUnit() == CurGroup[j])
- return true;
- }
-
- return false;
-}
-
-bool PPCDispatchGroupSBHazardRecognizer::isBCTRAfterSet(SUnit *SU) {
- const MCInstrDesc *MCID = DAG->getInstrDesc(SU);
- if (!MCID)
- return false;
-
- if (!MCID->isBranch())
- return false;
-
- // SU is a branch; for any predecessors in this dispatch group, with which we
- // have a data dependence and set the counter register, return true.
- for (unsigned i = 0, ie = (unsigned) SU->Preds.size(); i != ie; ++i) {
- const MCInstrDesc *PredMCID = DAG->getInstrDesc(SU->Preds[i].getSUnit());
- if (!PredMCID || PredMCID->getSchedClass() != PPC::Sched::IIC_SprMTSPR)
- continue;
-
- if (SU->Preds[i].isCtrl())
- continue;
-
- for (unsigned j = 0, je = CurGroup.size(); j != je; ++j)
- if (SU->Preds[i].getSUnit() == CurGroup[j])
- return true;
- }
-
- return false;
-}
-
-// FIXME: Remove this when we don't need this:
-namespace llvm { namespace PPC { extern int getNonRecordFormOpcode(uint16_t); } }
-
-// FIXME: A lot of code in PPCDispatchGroupSBHazardRecognizer is P7 specific.
-
-bool PPCDispatchGroupSBHazardRecognizer::mustComeFirst(const MCInstrDesc *MCID,
- unsigned &NSlots) {
- // FIXME: Indirectly, this information is contained in the itinerary, and
- // we should derive it from there instead of separately specifying it
- // here.
- unsigned IIC = MCID->getSchedClass();
- switch (IIC) {
- default:
- NSlots = 1;
- break;
- case PPC::Sched::IIC_IntDivW:
- case PPC::Sched::IIC_IntDivD:
- case PPC::Sched::IIC_LdStLoadUpd:
- case PPC::Sched::IIC_LdStLDU:
- case PPC::Sched::IIC_LdStLFDU:
- case PPC::Sched::IIC_LdStLFDUX:
- case PPC::Sched::IIC_LdStLHA:
- case PPC::Sched::IIC_LdStLHAU:
- case PPC::Sched::IIC_LdStLWA:
- case PPC::Sched::IIC_LdStSTU:
- case PPC::Sched::IIC_LdStSTFDU:
- NSlots = 2;
- break;
- case PPC::Sched::IIC_LdStLoadUpdX:
- case PPC::Sched::IIC_LdStLDUX:
- case PPC::Sched::IIC_LdStLHAUX:
- case PPC::Sched::IIC_LdStLWARX:
- case PPC::Sched::IIC_LdStLDARX:
- case PPC::Sched::IIC_LdStSTUX:
- case PPC::Sched::IIC_LdStSTDCX:
- case PPC::Sched::IIC_LdStSTWCX:
- case PPC::Sched::IIC_BrMCRX: // mtcr
- // FIXME: Add sync/isync (here and in the itinerary).
- NSlots = 4;
- break;
- }
-
- // FIXME: record-form instructions need a different itinerary class.
- if (NSlots == 1 && PPC::getNonRecordFormOpcode(MCID->getOpcode()) != -1)
- NSlots = 2;
-
- switch (IIC) {
- default:
- // All multi-slot instructions must come first.
- return NSlots > 1;
- case PPC::Sched::IIC_BrCR: // cr logicals
- case PPC::Sched::IIC_SprMFCR:
- case PPC::Sched::IIC_SprMFCRF:
- case PPC::Sched::IIC_SprMTSPR:
- return true;
- }
-}
-
-ScheduleHazardRecognizer::HazardType
-PPCDispatchGroupSBHazardRecognizer::getHazardType(SUnit *SU, int Stalls) {
- if (Stalls == 0 && isLoadAfterStore(SU))
- return NoopHazard;
-
- return ScoreboardHazardRecognizer::getHazardType(SU, Stalls);
-}
-
-bool PPCDispatchGroupSBHazardRecognizer::ShouldPreferAnother(SUnit *SU) {
- const MCInstrDesc *MCID = DAG->getInstrDesc(SU);
- unsigned NSlots;
- if (MCID && mustComeFirst(MCID, NSlots) && CurSlots)
- return true;
-
- return ScoreboardHazardRecognizer::ShouldPreferAnother(SU);
-}
-
-unsigned PPCDispatchGroupSBHazardRecognizer::PreEmitNoops(SUnit *SU) {
- // We only need to fill out a maximum of 5 slots here: The 6th slot could
- // only be a second branch, and otherwise the next instruction will start a
- // new group.
- if (isLoadAfterStore(SU) && CurSlots < 6) {
- unsigned Directive =
- DAG->MF.getSubtarget<PPCSubtarget>().getCPUDirective();
- // If we're using a special group-terminating nop, then we need only one.
- // FIXME: the same for P9 as previous gen until POWER9 scheduling is ready
- if (Directive == PPC::DIR_PWR6 || Directive == PPC::DIR_PWR7 ||
- Directive == PPC::DIR_PWR8 || Directive == PPC::DIR_PWR9)
- return 1;
-
- return 5 - CurSlots;
- }
-
- return ScoreboardHazardRecognizer::PreEmitNoops(SU);
-}
-
-void PPCDispatchGroupSBHazardRecognizer::EmitInstruction(SUnit *SU) {
- const MCInstrDesc *MCID = DAG->getInstrDesc(SU);
- if (MCID) {
- if (CurSlots == 5 || (MCID->isBranch() && CurBranches == 1)) {
- CurGroup.clear();
- CurSlots = CurBranches = 0;
- } else {
- LLVM_DEBUG(dbgs() << "**** Adding to dispatch group: ");
- LLVM_DEBUG(DAG->dumpNode(*SU));
-
- unsigned NSlots;
- bool MustBeFirst = mustComeFirst(MCID, NSlots);
-
- // If this instruction must come first, but does not, then it starts a
- // new group.
- if (MustBeFirst && CurSlots) {
- CurSlots = CurBranches = 0;
- CurGroup.clear();
- }
-
- CurSlots += NSlots;
- CurGroup.push_back(SU);
-
- if (MCID->isBranch())
- ++CurBranches;
- }
- }
-
- return ScoreboardHazardRecognizer::EmitInstruction(SU);
-}
-
-void PPCDispatchGroupSBHazardRecognizer::AdvanceCycle() {
- return ScoreboardHazardRecognizer::AdvanceCycle();
-}
-
-void PPCDispatchGroupSBHazardRecognizer::RecedeCycle() {
- llvm_unreachable("Bottom-up scheduling not supported");
-}
-
-void PPCDispatchGroupSBHazardRecognizer::Reset() {
- CurGroup.clear();
- CurSlots = CurBranches = 0;
- return ScoreboardHazardRecognizer::Reset();
-}
-
-void PPCDispatchGroupSBHazardRecognizer::EmitNoop() {
- unsigned Directive =
- DAG->MF.getSubtarget<PPCSubtarget>().getCPUDirective();
- // If the group has now filled all of its slots, or if we're using a special
- // group-terminating nop, the group is complete.
- // FIXME: the same for P9 as previous gen until POWER9 scheduling is ready
- if (Directive == PPC::DIR_PWR6 || Directive == PPC::DIR_PWR7 ||
- Directive == PPC::DIR_PWR8 || Directive == PPC::DIR_PWR9 ||
- CurSlots == 6) {
- CurGroup.clear();
- CurSlots = CurBranches = 0;
- } else {
- CurGroup.push_back(nullptr);
- ++CurSlots;
- }
-}
-
-//===----------------------------------------------------------------------===//
-// PowerPC 970 Hazard Recognizer
-//
-// This models the dispatch group formation of the PPC970 processor. Dispatch
-// groups are bundles of up to five instructions that can contain various mixes
-// of instructions. The PPC970 can dispatch a peak of 4 non-branch and one
-// branch instruction per-cycle.
-//
-// There are a number of restrictions to dispatch group formation: some
-// instructions can only be issued in the first slot of a dispatch group, & some
-// instructions fill an entire dispatch group. Additionally, only branches can
-// issue in the 5th (last) slot.
-//
-// Finally, there are a number of "structural" hazards on the PPC970. These
-// conditions cause large performance penalties due to misprediction, recovery,
-// and replay logic that has to happen. These cases include setting a CTR and
-// branching through it in the same dispatch group, and storing to an address,
-// then loading from the same address within a dispatch group. To avoid these
-// conditions, we insert no-op instructions when appropriate.
-//
-// FIXME: This is missing some significant cases:
-// 1. Modeling of microcoded instructions.
-// 2. Handling of serialized operations.
-// 3. Handling of the esoteric cases in "Resource-based Instruction Grouping".
-//
-
-PPCHazardRecognizer970::PPCHazardRecognizer970(const ScheduleDAG &DAG)
- : DAG(DAG) {
- EndDispatchGroup();
-}
-
-void PPCHazardRecognizer970::EndDispatchGroup() {
- LLVM_DEBUG(errs() << "=== Start of dispatch group\n");
- NumIssued = 0;
-
- // Structural hazard info.
- HasCTRSet = false;
- NumStores = 0;
-}
-
-
-PPCII::PPC970_Unit
-PPCHazardRecognizer970::GetInstrType(unsigned Opcode,
- bool &isFirst, bool &isSingle,
- bool &isCracked,
- bool &isLoad, bool &isStore) {
- const MCInstrDesc &MCID = DAG.TII->get(Opcode);
-
- isLoad = MCID.mayLoad();
- isStore = MCID.mayStore();
-
- uint64_t TSFlags = MCID.TSFlags;
-
- isFirst = TSFlags & PPCII::PPC970_First;
- isSingle = TSFlags & PPCII::PPC970_Single;
- isCracked = TSFlags & PPCII::PPC970_Cracked;
- return (PPCII::PPC970_Unit)(TSFlags & PPCII::PPC970_Mask);
-}
-
-/// isLoadOfStoredAddress - If we have a load from the previously stored pointer
-/// as indicated by StorePtr1/StorePtr2/StoreSize, return true.
-bool PPCHazardRecognizer970::
-isLoadOfStoredAddress(uint64_t LoadSize, int64_t LoadOffset,
- const Value *LoadValue) const {
- for (unsigned i = 0, e = NumStores; i != e; ++i) {
- // Handle exact and commuted addresses.
- if (LoadValue == StoreValue[i] && LoadOffset == StoreOffset[i])
- return true;
-
- // Okay, we don't have an exact match, if this is an indexed offset, see if
- // we have overlap (which happens during fp->int conversion for example).
- if (StoreValue[i] == LoadValue) {
- // Okay the base pointers match, so we have [c1+r] vs [c2+r]. Check
- // to see if the load and store actually overlap.
- if (StoreOffset[i] < LoadOffset) {
- if (int64_t(StoreOffset[i]+StoreSize[i]) > LoadOffset) return true;
- } else {
- if (int64_t(LoadOffset+LoadSize) > StoreOffset[i]) return true;
- }
- }
- }
- return false;
-}
-
-/// getHazardType - We return hazard for any non-branch instruction that would
-/// terminate the dispatch group. We turn NoopHazard for any
-/// instructions that wouldn't terminate the dispatch group that would cause a
-/// pipeline flush.
-ScheduleHazardRecognizer::HazardType PPCHazardRecognizer970::
-getHazardType(SUnit *SU, int Stalls) {
- assert(Stalls == 0 && "PPC hazards don't support scoreboard lookahead");
-
- MachineInstr *MI = SU->getInstr();
-
- if (MI->isDebugInstr())
- return NoHazard;
-
- unsigned Opcode = MI->getOpcode();
- bool isFirst, isSingle, isCracked, isLoad, isStore;
- PPCII::PPC970_Unit InstrType =
- GetInstrType(Opcode, isFirst, isSingle, isCracked,
- isLoad, isStore);
- if (InstrType == PPCII::PPC970_Pseudo) return NoHazard;
-
- // We can only issue a PPC970_First/PPC970_Single instruction (such as
- // crand/mtspr/etc) if this is the first cycle of the dispatch group.
- if (NumIssued != 0 && (isFirst || isSingle))
- return Hazard;
-
- // If this instruction is cracked into two ops by the decoder, we know that
- // it is not a branch and that it cannot issue if 3 other instructions are
- // already in the dispatch group.
- if (isCracked && NumIssued > 2)
- return Hazard;
-
- switch (InstrType) {
- default: llvm_unreachable("Unknown instruction type!");
- case PPCII::PPC970_FXU:
- case PPCII::PPC970_LSU:
- case PPCII::PPC970_FPU:
- case PPCII::PPC970_VALU:
- case PPCII::PPC970_VPERM:
- // We can only issue a branch as the last instruction in a group.
- if (NumIssued == 4) return Hazard;
- break;
- case PPCII::PPC970_CRU:
- // We can only issue a CR instruction in the first two slots.
- if (NumIssued >= 2) return Hazard;
- break;
- case PPCII::PPC970_BRU:
- break;
- }
-
- // Do not allow MTCTR and BCTRL to be in the same dispatch group.
- if (HasCTRSet && Opcode == PPC::BCTRL)
- return NoopHazard;
-
- // If this is a load following a store, make sure it's not to the same or
- // overlapping address.
- if (isLoad && NumStores && !MI->memoperands_empty()) {
- MachineMemOperand *MO = *MI->memoperands_begin();
- if (isLoadOfStoredAddress(MO->getSize(),
- MO->getOffset(), MO->getValue()))
- return NoopHazard;
- }
-
- return NoHazard;
-}
-
-void PPCHazardRecognizer970::EmitInstruction(SUnit *SU) {
- MachineInstr *MI = SU->getInstr();
-
- if (MI->isDebugInstr())
- return;
-
- unsigned Opcode = MI->getOpcode();
- bool isFirst, isSingle, isCracked, isLoad, isStore;
- PPCII::PPC970_Unit InstrType =
- GetInstrType(Opcode, isFirst, isSingle, isCracked,
- isLoad, isStore);
- if (InstrType == PPCII::PPC970_Pseudo) return;
-
- // Update structural hazard information.
- if (Opcode == PPC::MTCTR || Opcode == PPC::MTCTR8) HasCTRSet = true;
-
- // Track the address stored to.
- if (isStore && NumStores < 4 && !MI->memoperands_empty()) {
- MachineMemOperand *MO = *MI->memoperands_begin();
- StoreSize[NumStores] = MO->getSize();
- StoreOffset[NumStores] = MO->getOffset();
- StoreValue[NumStores] = MO->getValue();
- ++NumStores;
- }
-
- if (InstrType == PPCII::PPC970_BRU || isSingle)
- NumIssued = 4; // Terminate a d-group.
- ++NumIssued;
-
- // If this instruction is cracked into two ops by the decoder, remember that
- // we issued two pieces.
- if (isCracked)
- ++NumIssued;
-
- if (NumIssued == 5)
- EndDispatchGroup();
-}
-
-void PPCHazardRecognizer970::AdvanceCycle() {
- assert(NumIssued < 5 && "Illegal dispatch group!");
- ++NumIssued;
- if (NumIssued == 5)
- EndDispatchGroup();
-}
-
-void PPCHazardRecognizer970::Reset() {
- EndDispatchGroup();
-}
-
+//===-- PPCHazardRecognizers.cpp - PowerPC Hazard Recognizer Impls --------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements hazard recognizers for scheduling on PowerPC processors.
+//
+//===----------------------------------------------------------------------===//
+
+#include "PPCHazardRecognizers.h"
+#include "PPCInstrInfo.h"
+#include "PPCSubtarget.h"
+#include "llvm/CodeGen/ScheduleDAG.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace llvm;
+
+#define DEBUG_TYPE "pre-RA-sched"
+
+bool PPCDispatchGroupSBHazardRecognizer::isLoadAfterStore(SUnit *SU) {
+ // FIXME: Move this.
+ if (isBCTRAfterSet(SU))
+ return true;
+
+ const MCInstrDesc *MCID = DAG->getInstrDesc(SU);
+ if (!MCID)
+ return false;
+
+ if (!MCID->mayLoad())
+ return false;
+
+ // SU is a load; for any predecessors in this dispatch group, that are stores,
+ // and with which we have an ordering dependency, return true.
+ for (unsigned i = 0, ie = (unsigned) SU->Preds.size(); i != ie; ++i) {
+ const MCInstrDesc *PredMCID = DAG->getInstrDesc(SU->Preds[i].getSUnit());
+ if (!PredMCID || !PredMCID->mayStore())
+ continue;
+
+ if (!SU->Preds[i].isNormalMemory() && !SU->Preds[i].isBarrier())
+ continue;
+
+ for (unsigned j = 0, je = CurGroup.size(); j != je; ++j)
+ if (SU->Preds[i].getSUnit() == CurGroup[j])
+ return true;
+ }
+
+ return false;
+}
+
+bool PPCDispatchGroupSBHazardRecognizer::isBCTRAfterSet(SUnit *SU) {
+ const MCInstrDesc *MCID = DAG->getInstrDesc(SU);
+ if (!MCID)
+ return false;
+
+ if (!MCID->isBranch())
+ return false;
+
+ // SU is a branch; for any predecessors in this dispatch group, with which we
+ // have a data dependence and set the counter register, return true.
+ for (unsigned i = 0, ie = (unsigned) SU->Preds.size(); i != ie; ++i) {
+ const MCInstrDesc *PredMCID = DAG->getInstrDesc(SU->Preds[i].getSUnit());
+ if (!PredMCID || PredMCID->getSchedClass() != PPC::Sched::IIC_SprMTSPR)
+ continue;
+
+ if (SU->Preds[i].isCtrl())
+ continue;
+
+ for (unsigned j = 0, je = CurGroup.size(); j != je; ++j)
+ if (SU->Preds[i].getSUnit() == CurGroup[j])
+ return true;
+ }
+
+ return false;
+}
+
+// FIXME: Remove this when we don't need this:
+namespace llvm { namespace PPC { extern int getNonRecordFormOpcode(uint16_t); } }
+
+// FIXME: A lot of code in PPCDispatchGroupSBHazardRecognizer is P7 specific.
+
+bool PPCDispatchGroupSBHazardRecognizer::mustComeFirst(const MCInstrDesc *MCID,
+ unsigned &NSlots) {
+ // FIXME: Indirectly, this information is contained in the itinerary, and
+ // we should derive it from there instead of separately specifying it
+ // here.
+ unsigned IIC = MCID->getSchedClass();
+ switch (IIC) {
+ default:
+ NSlots = 1;
+ break;
+ case PPC::Sched::IIC_IntDivW:
+ case PPC::Sched::IIC_IntDivD:
+ case PPC::Sched::IIC_LdStLoadUpd:
+ case PPC::Sched::IIC_LdStLDU:
+ case PPC::Sched::IIC_LdStLFDU:
+ case PPC::Sched::IIC_LdStLFDUX:
+ case PPC::Sched::IIC_LdStLHA:
+ case PPC::Sched::IIC_LdStLHAU:
+ case PPC::Sched::IIC_LdStLWA:
+ case PPC::Sched::IIC_LdStSTU:
+ case PPC::Sched::IIC_LdStSTFDU:
+ NSlots = 2;
+ break;
+ case PPC::Sched::IIC_LdStLoadUpdX:
+ case PPC::Sched::IIC_LdStLDUX:
+ case PPC::Sched::IIC_LdStLHAUX:
+ case PPC::Sched::IIC_LdStLWARX:
+ case PPC::Sched::IIC_LdStLDARX:
+ case PPC::Sched::IIC_LdStSTUX:
+ case PPC::Sched::IIC_LdStSTDCX:
+ case PPC::Sched::IIC_LdStSTWCX:
+ case PPC::Sched::IIC_BrMCRX: // mtcr
+ // FIXME: Add sync/isync (here and in the itinerary).
+ NSlots = 4;
+ break;
+ }
+
+ // FIXME: record-form instructions need a different itinerary class.
+ if (NSlots == 1 && PPC::getNonRecordFormOpcode(MCID->getOpcode()) != -1)
+ NSlots = 2;
+
+ switch (IIC) {
+ default:
+ // All multi-slot instructions must come first.
+ return NSlots > 1;
+ case PPC::Sched::IIC_BrCR: // cr logicals
+ case PPC::Sched::IIC_SprMFCR:
+ case PPC::Sched::IIC_SprMFCRF:
+ case PPC::Sched::IIC_SprMTSPR:
+ return true;
+ }
+}
+
+ScheduleHazardRecognizer::HazardType
+PPCDispatchGroupSBHazardRecognizer::getHazardType(SUnit *SU, int Stalls) {
+ if (Stalls == 0 && isLoadAfterStore(SU))
+ return NoopHazard;
+
+ return ScoreboardHazardRecognizer::getHazardType(SU, Stalls);
+}
+
+bool PPCDispatchGroupSBHazardRecognizer::ShouldPreferAnother(SUnit *SU) {
+ const MCInstrDesc *MCID = DAG->getInstrDesc(SU);
+ unsigned NSlots;
+ if (MCID && mustComeFirst(MCID, NSlots) && CurSlots)
+ return true;
+
+ return ScoreboardHazardRecognizer::ShouldPreferAnother(SU);
+}
+
+unsigned PPCDispatchGroupSBHazardRecognizer::PreEmitNoops(SUnit *SU) {
+ // We only need to fill out a maximum of 5 slots here: The 6th slot could
+ // only be a second branch, and otherwise the next instruction will start a
+ // new group.
+ if (isLoadAfterStore(SU) && CurSlots < 6) {
+ unsigned Directive =
+ DAG->MF.getSubtarget<PPCSubtarget>().getCPUDirective();
+ // If we're using a special group-terminating nop, then we need only one.
+ // FIXME: the same for P9 as previous gen until POWER9 scheduling is ready
+ if (Directive == PPC::DIR_PWR6 || Directive == PPC::DIR_PWR7 ||
+ Directive == PPC::DIR_PWR8 || Directive == PPC::DIR_PWR9)
+ return 1;
+
+ return 5 - CurSlots;
+ }
+
+ return ScoreboardHazardRecognizer::PreEmitNoops(SU);
+}
+
+void PPCDispatchGroupSBHazardRecognizer::EmitInstruction(SUnit *SU) {
+ const MCInstrDesc *MCID = DAG->getInstrDesc(SU);
+ if (MCID) {
+ if (CurSlots == 5 || (MCID->isBranch() && CurBranches == 1)) {
+ CurGroup.clear();
+ CurSlots = CurBranches = 0;
+ } else {
+ LLVM_DEBUG(dbgs() << "**** Adding to dispatch group: ");
+ LLVM_DEBUG(DAG->dumpNode(*SU));
+
+ unsigned NSlots;
+ bool MustBeFirst = mustComeFirst(MCID, NSlots);
+
+ // If this instruction must come first, but does not, then it starts a
+ // new group.
+ if (MustBeFirst && CurSlots) {
+ CurSlots = CurBranches = 0;
+ CurGroup.clear();
+ }
+
+ CurSlots += NSlots;
+ CurGroup.push_back(SU);
+
+ if (MCID->isBranch())
+ ++CurBranches;
+ }
+ }
+
+ return ScoreboardHazardRecognizer::EmitInstruction(SU);
+}
+
+void PPCDispatchGroupSBHazardRecognizer::AdvanceCycle() {
+ return ScoreboardHazardRecognizer::AdvanceCycle();
+}
+
+void PPCDispatchGroupSBHazardRecognizer::RecedeCycle() {
+ llvm_unreachable("Bottom-up scheduling not supported");
+}
+
+void PPCDispatchGroupSBHazardRecognizer::Reset() {
+ CurGroup.clear();
+ CurSlots = CurBranches = 0;
+ return ScoreboardHazardRecognizer::Reset();
+}
+
+void PPCDispatchGroupSBHazardRecognizer::EmitNoop() {
+ unsigned Directive =
+ DAG->MF.getSubtarget<PPCSubtarget>().getCPUDirective();
+ // If the group has now filled all of its slots, or if we're using a special
+ // group-terminating nop, the group is complete.
+ // FIXME: the same for P9 as previous gen until POWER9 scheduling is ready
+ if (Directive == PPC::DIR_PWR6 || Directive == PPC::DIR_PWR7 ||
+ Directive == PPC::DIR_PWR8 || Directive == PPC::DIR_PWR9 ||
+ CurSlots == 6) {
+ CurGroup.clear();
+ CurSlots = CurBranches = 0;
+ } else {
+ CurGroup.push_back(nullptr);
+ ++CurSlots;
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// PowerPC 970 Hazard Recognizer
+//
+// This models the dispatch group formation of the PPC970 processor. Dispatch
+// groups are bundles of up to five instructions that can contain various mixes
+// of instructions. The PPC970 can dispatch a peak of 4 non-branch and one
+// branch instruction per-cycle.
+//
+// There are a number of restrictions to dispatch group formation: some
+// instructions can only be issued in the first slot of a dispatch group, & some
+// instructions fill an entire dispatch group. Additionally, only branches can
+// issue in the 5th (last) slot.
+//
+// Finally, there are a number of "structural" hazards on the PPC970. These
+// conditions cause large performance penalties due to misprediction, recovery,
+// and replay logic that has to happen. These cases include setting a CTR and
+// branching through it in the same dispatch group, and storing to an address,
+// then loading from the same address within a dispatch group. To avoid these
+// conditions, we insert no-op instructions when appropriate.
+//
+// FIXME: This is missing some significant cases:
+// 1. Modeling of microcoded instructions.
+// 2. Handling of serialized operations.
+// 3. Handling of the esoteric cases in "Resource-based Instruction Grouping".
+//
+
+PPCHazardRecognizer970::PPCHazardRecognizer970(const ScheduleDAG &DAG)
+ : DAG(DAG) {
+ EndDispatchGroup();
+}
+
+void PPCHazardRecognizer970::EndDispatchGroup() {
+ LLVM_DEBUG(errs() << "=== Start of dispatch group\n");
+ NumIssued = 0;
+
+ // Structural hazard info.
+ HasCTRSet = false;
+ NumStores = 0;
+}
+
+
+PPCII::PPC970_Unit
+PPCHazardRecognizer970::GetInstrType(unsigned Opcode,
+ bool &isFirst, bool &isSingle,
+ bool &isCracked,
+ bool &isLoad, bool &isStore) {
+ const MCInstrDesc &MCID = DAG.TII->get(Opcode);
+
+ isLoad = MCID.mayLoad();
+ isStore = MCID.mayStore();
+
+ uint64_t TSFlags = MCID.TSFlags;
+
+ isFirst = TSFlags & PPCII::PPC970_First;
+ isSingle = TSFlags & PPCII::PPC970_Single;
+ isCracked = TSFlags & PPCII::PPC970_Cracked;
+ return (PPCII::PPC970_Unit)(TSFlags & PPCII::PPC970_Mask);
+}
+
+/// isLoadOfStoredAddress - If we have a load from the previously stored pointer
+/// as indicated by StorePtr1/StorePtr2/StoreSize, return true.
+bool PPCHazardRecognizer970::
+isLoadOfStoredAddress(uint64_t LoadSize, int64_t LoadOffset,
+ const Value *LoadValue) const {
+ for (unsigned i = 0, e = NumStores; i != e; ++i) {
+ // Handle exact and commuted addresses.
+ if (LoadValue == StoreValue[i] && LoadOffset == StoreOffset[i])
+ return true;
+
+ // Okay, we don't have an exact match, if this is an indexed offset, see if
+ // we have overlap (which happens during fp->int conversion for example).
+ if (StoreValue[i] == LoadValue) {
+ // Okay the base pointers match, so we have [c1+r] vs [c2+r]. Check
+ // to see if the load and store actually overlap.
+ if (StoreOffset[i] < LoadOffset) {
+ if (int64_t(StoreOffset[i]+StoreSize[i]) > LoadOffset) return true;
+ } else {
+ if (int64_t(LoadOffset+LoadSize) > StoreOffset[i]) return true;
+ }
+ }
+ }
+ return false;
+}
+
+/// getHazardType - We return hazard for any non-branch instruction that would
+/// terminate the dispatch group. We turn NoopHazard for any
+/// instructions that wouldn't terminate the dispatch group that would cause a
+/// pipeline flush.
+ScheduleHazardRecognizer::HazardType PPCHazardRecognizer970::
+getHazardType(SUnit *SU, int Stalls) {
+ assert(Stalls == 0 && "PPC hazards don't support scoreboard lookahead");
+
+ MachineInstr *MI = SU->getInstr();
+
+ if (MI->isDebugInstr())
+ return NoHazard;
+
+ unsigned Opcode = MI->getOpcode();
+ bool isFirst, isSingle, isCracked, isLoad, isStore;
+ PPCII::PPC970_Unit InstrType =
+ GetInstrType(Opcode, isFirst, isSingle, isCracked,
+ isLoad, isStore);
+ if (InstrType == PPCII::PPC970_Pseudo) return NoHazard;
+
+ // We can only issue a PPC970_First/PPC970_Single instruction (such as
+ // crand/mtspr/etc) if this is the first cycle of the dispatch group.
+ if (NumIssued != 0 && (isFirst || isSingle))
+ return Hazard;
+
+ // If this instruction is cracked into two ops by the decoder, we know that
+ // it is not a branch and that it cannot issue if 3 other instructions are
+ // already in the dispatch group.
+ if (isCracked && NumIssued > 2)
+ return Hazard;
+
+ switch (InstrType) {
+ default: llvm_unreachable("Unknown instruction type!");
+ case PPCII::PPC970_FXU:
+ case PPCII::PPC970_LSU:
+ case PPCII::PPC970_FPU:
+ case PPCII::PPC970_VALU:
+ case PPCII::PPC970_VPERM:
+ // We can only issue a branch as the last instruction in a group.
+ if (NumIssued == 4) return Hazard;
+ break;
+ case PPCII::PPC970_CRU:
+ // We can only issue a CR instruction in the first two slots.
+ if (NumIssued >= 2) return Hazard;
+ break;
+ case PPCII::PPC970_BRU:
+ break;
+ }
+
+ // Do not allow MTCTR and BCTRL to be in the same dispatch group.
+ if (HasCTRSet && Opcode == PPC::BCTRL)
+ return NoopHazard;
+
+ // If this is a load following a store, make sure it's not to the same or
+ // overlapping address.
+ if (isLoad && NumStores && !MI->memoperands_empty()) {
+ MachineMemOperand *MO = *MI->memoperands_begin();
+ if (isLoadOfStoredAddress(MO->getSize(),
+ MO->getOffset(), MO->getValue()))
+ return NoopHazard;
+ }
+
+ return NoHazard;
+}
+
+void PPCHazardRecognizer970::EmitInstruction(SUnit *SU) {
+ MachineInstr *MI = SU->getInstr();
+
+ if (MI->isDebugInstr())
+ return;
+
+ unsigned Opcode = MI->getOpcode();
+ bool isFirst, isSingle, isCracked, isLoad, isStore;
+ PPCII::PPC970_Unit InstrType =
+ GetInstrType(Opcode, isFirst, isSingle, isCracked,
+ isLoad, isStore);
+ if (InstrType == PPCII::PPC970_Pseudo) return;
+
+ // Update structural hazard information.
+ if (Opcode == PPC::MTCTR || Opcode == PPC::MTCTR8) HasCTRSet = true;
+
+ // Track the address stored to.
+ if (isStore && NumStores < 4 && !MI->memoperands_empty()) {
+ MachineMemOperand *MO = *MI->memoperands_begin();
+ StoreSize[NumStores] = MO->getSize();
+ StoreOffset[NumStores] = MO->getOffset();
+ StoreValue[NumStores] = MO->getValue();
+ ++NumStores;
+ }
+
+ if (InstrType == PPCII::PPC970_BRU || isSingle)
+ NumIssued = 4; // Terminate a d-group.
+ ++NumIssued;
+
+ // If this instruction is cracked into two ops by the decoder, remember that
+ // we issued two pieces.
+ if (isCracked)
+ ++NumIssued;
+
+ if (NumIssued == 5)
+ EndDispatchGroup();
+}
+
+void PPCHazardRecognizer970::AdvanceCycle() {
+ assert(NumIssued < 5 && "Illegal dispatch group!");
+ ++NumIssued;
+ if (NumIssued == 5)
+ EndDispatchGroup();
+}
+
+void PPCHazardRecognizer970::Reset() {
+ EndDispatchGroup();
+}
+