| //=-- 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 <string> |
| |
| 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<int, 0> 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 *SU, 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 */ |