|  | //=-- 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 */ |