//=-- SystemZHazardRecognizer.h - SystemZ Hazard Recognizer -----*- C++ -*-===// // // 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 declares a hazard recognizer for the SystemZ scheduler. // // This class is used by the SystemZ scheduling strategy to maintain // the state during scheduling, and provide cost functions for // scheduling candidates. This includes: // // * Decoder grouping. A decoder group can maximally hold 3 uops, and // instructions that always begin a new group should be scheduled when // the current decoder group is empty. // * Processor resources usage. It is beneficial to balance the use of // resources. // // A goal is to consider all instructions, also those outside of any // scheduling region. Such instructions are "advanced" past and include // single instructions before a scheduling region, branches etc. // // A block that has only one predecessor continues scheduling with the state // of it (which may be updated by emitting branches). // // ===---------------------------------------------------------------------===// #ifndef LLVM_LIB_TARGET_SYSTEMZ_SYSTEMZHAZARDRECOGNIZER_H #define LLVM_LIB_TARGET_SYSTEMZ_SYSTEMZHAZARDRECOGNIZER_H #include "SystemZSubtarget.h" #include "llvm/ADT/SmallVector.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineScheduler.h" #include "llvm/CodeGen/ScheduleHazardRecognizer.h" #include "llvm/MC/MCInstrDesc.h" #include "llvm/Support/raw_ostream.h" #include namespace llvm { /// SystemZHazardRecognizer maintains the state for one MBB during scheduling. class SystemZHazardRecognizer : public ScheduleHazardRecognizer { const SystemZInstrInfo *TII; const TargetSchedModel *SchedModel; /// Keep track of the number of decoder slots used in the current /// decoder group. unsigned CurrGroupSize; /// True if an instruction with four reg operands have been scheduled into /// the current decoder group. bool CurrGroupHas4RegOps; /// The tracking of resources here are quite similar to the common /// code use of a critical resource. However, z13 differs in the way /// that it has two processor sides which may be interesting to /// model in the future (a work in progress). /// Counters for the number of uops scheduled per processor /// resource. SmallVector ProcResourceCounters; /// This is the resource with the greatest queue, which the /// scheduler tries to avoid. unsigned CriticalResourceIdx; /// Return the number of decoder slots MI requires. inline unsigned getNumDecoderSlots(SUnit *SU) const; /// Return true if MI fits into current decoder group. bool fitsIntoCurrentGroup(SUnit *SU) const; /// Return true if this instruction has four register operands. bool has4RegOps(const MachineInstr *MI) const; /// Two decoder groups per cycle are formed (for z13), meaning 2x3 /// instructions. This function returns a number between 0 and 5, /// representing the current decoder slot of the current cycle. If an SU /// is passed which will begin a new decoder group, the returned value is /// the cycle index of the next group. unsigned getCurrCycleIdx(SUnit *SU = nullptr) const; /// LastFPdOpCycleIdx stores the numbeer returned by getCurrCycleIdx() /// when a stalling operation is scheduled (which uses the FPd resource). unsigned LastFPdOpCycleIdx; /// A counter of decoder groups scheduled. unsigned GrpCount; unsigned getCurrGroupSize() {return CurrGroupSize;}; /// Start next decoder group. void nextGroup(); /// Clear all counters for processor resources. void clearProcResCounters(); /// With the goal of alternating processor sides for stalling (FPd) /// ops, return true if it seems good to schedule an FPd op next. bool isFPdOpPreferred_distance(SUnit *SU) const; /// Last emitted instruction or nullptr. MachineInstr *LastEmittedMI; public: SystemZHazardRecognizer(const SystemZInstrInfo *tii, const TargetSchedModel *SM) : TII(tii), SchedModel(SM) { Reset(); } HazardType getHazardType(SUnit *m, int Stalls = 0) override; void Reset() override; void EmitInstruction(SUnit *SU) override; /// Resolves and cache a resolved scheduling class for an SUnit. const MCSchedClassDesc *getSchedClass(SUnit *SU) const { if (!SU->SchedClass && SchedModel->hasInstrSchedModel()) SU->SchedClass = SchedModel->resolveSchedClass(SU->getInstr()); return SU->SchedClass; } /// Wrap a non-scheduled instruction in an SU and emit it. void emitInstruction(MachineInstr *MI, bool TakenBranch = false); // Cost functions used by SystemZPostRASchedStrategy while // evaluating candidates. /// Return the cost of decoder grouping for SU. If SU must start a /// new decoder group, this is negative if this fits the schedule or /// positive if it would mean ending a group prematurely. For normal /// instructions this returns 0. int groupingCost(SUnit *SU) const; /// Return the cost of SU in regards to processor resources usage. /// A positive value means it would be better to wait with SU, while /// a negative value means it would be good to schedule SU next. int resourcesCost(SUnit *SU); #ifndef NDEBUG // Debug dumping. std::string CurGroupDbg; // current group as text void dumpSU(SUnit *SU, raw_ostream &OS) const; void dumpCurrGroup(std::string Msg = "") const; void dumpProcResourceCounters() const; void dumpState() const; #endif MachineBasicBlock::iterator getLastEmittedMI() { return LastEmittedMI; } /// Copy counters from end of single predecessor. void copyState(SystemZHazardRecognizer *Incoming); }; } // namespace llvm #endif /* LLVM_LIB_TARGET_SYSTEMZ_SYSTEMZHAZARDRECOGNIZER_H */