10b57cec5SDimitry Andric //=-- SystemZHazardRecognizer.h - SystemZ Hazard Recognizer -----*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This file declares a hazard recognizer for the SystemZ scheduler. 100b57cec5SDimitry Andric // 110b57cec5SDimitry Andric // This class is used by the SystemZ scheduling strategy to maintain 120b57cec5SDimitry Andric // the state during scheduling, and provide cost functions for 130b57cec5SDimitry Andric // scheduling candidates. This includes: 140b57cec5SDimitry Andric // 150b57cec5SDimitry Andric // * Decoder grouping. A decoder group can maximally hold 3 uops, and 160b57cec5SDimitry Andric // instructions that always begin a new group should be scheduled when 170b57cec5SDimitry Andric // the current decoder group is empty. 180b57cec5SDimitry Andric // * Processor resources usage. It is beneficial to balance the use of 190b57cec5SDimitry Andric // resources. 200b57cec5SDimitry Andric // 210b57cec5SDimitry Andric // A goal is to consider all instructions, also those outside of any 220b57cec5SDimitry Andric // scheduling region. Such instructions are "advanced" past and include 230b57cec5SDimitry Andric // single instructions before a scheduling region, branches etc. 240b57cec5SDimitry Andric // 250b57cec5SDimitry Andric // A block that has only one predecessor continues scheduling with the state 260b57cec5SDimitry Andric // of it (which may be updated by emitting branches). 270b57cec5SDimitry Andric // 280b57cec5SDimitry Andric // ===---------------------------------------------------------------------===// 290b57cec5SDimitry Andric 300b57cec5SDimitry Andric #ifndef LLVM_LIB_TARGET_SYSTEMZ_SYSTEMZHAZARDRECOGNIZER_H 310b57cec5SDimitry Andric #define LLVM_LIB_TARGET_SYSTEMZ_SYSTEMZHAZARDRECOGNIZER_H 320b57cec5SDimitry Andric 330b57cec5SDimitry Andric #include "SystemZSubtarget.h" 340b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h" 350b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h" 360b57cec5SDimitry Andric #include "llvm/CodeGen/MachineScheduler.h" 370b57cec5SDimitry Andric #include "llvm/CodeGen/ScheduleHazardRecognizer.h" 380b57cec5SDimitry Andric #include "llvm/MC/MCInstrDesc.h" 390b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 400b57cec5SDimitry Andric #include <string> 410b57cec5SDimitry Andric 420b57cec5SDimitry Andric namespace llvm { 430b57cec5SDimitry Andric 440b57cec5SDimitry Andric /// SystemZHazardRecognizer maintains the state for one MBB during scheduling. 450b57cec5SDimitry Andric class SystemZHazardRecognizer : public ScheduleHazardRecognizer { 460b57cec5SDimitry Andric 470b57cec5SDimitry Andric const SystemZInstrInfo *TII; 480b57cec5SDimitry Andric const TargetSchedModel *SchedModel; 490b57cec5SDimitry Andric 500b57cec5SDimitry Andric /// Keep track of the number of decoder slots used in the current 510b57cec5SDimitry Andric /// decoder group. 520b57cec5SDimitry Andric unsigned CurrGroupSize; 530b57cec5SDimitry Andric 540b57cec5SDimitry Andric /// True if an instruction with four reg operands have been scheduled into 550b57cec5SDimitry Andric /// the current decoder group. 560b57cec5SDimitry Andric bool CurrGroupHas4RegOps; 570b57cec5SDimitry Andric 580b57cec5SDimitry Andric /// The tracking of resources here are quite similar to the common 590b57cec5SDimitry Andric /// code use of a critical resource. However, z13 differs in the way 600b57cec5SDimitry Andric /// that it has two processor sides which may be interesting to 610b57cec5SDimitry Andric /// model in the future (a work in progress). 620b57cec5SDimitry Andric 630b57cec5SDimitry Andric /// Counters for the number of uops scheduled per processor 640b57cec5SDimitry Andric /// resource. 650b57cec5SDimitry Andric SmallVector<int, 0> ProcResourceCounters; 660b57cec5SDimitry Andric 670b57cec5SDimitry Andric /// This is the resource with the greatest queue, which the 680b57cec5SDimitry Andric /// scheduler tries to avoid. 690b57cec5SDimitry Andric unsigned CriticalResourceIdx; 700b57cec5SDimitry Andric 710b57cec5SDimitry Andric /// Return the number of decoder slots MI requires. 720b57cec5SDimitry Andric inline unsigned getNumDecoderSlots(SUnit *SU) const; 730b57cec5SDimitry Andric 740b57cec5SDimitry Andric /// Return true if MI fits into current decoder group. 750b57cec5SDimitry Andric bool fitsIntoCurrentGroup(SUnit *SU) const; 760b57cec5SDimitry Andric 770b57cec5SDimitry Andric /// Return true if this instruction has four register operands. 780b57cec5SDimitry Andric bool has4RegOps(const MachineInstr *MI) const; 790b57cec5SDimitry Andric 800b57cec5SDimitry Andric /// Two decoder groups per cycle are formed (for z13), meaning 2x3 810b57cec5SDimitry Andric /// instructions. This function returns a number between 0 and 5, 820b57cec5SDimitry Andric /// representing the current decoder slot of the current cycle. If an SU 830b57cec5SDimitry Andric /// is passed which will begin a new decoder group, the returned value is 840b57cec5SDimitry Andric /// the cycle index of the next group. 850b57cec5SDimitry Andric unsigned getCurrCycleIdx(SUnit *SU = nullptr) const; 860b57cec5SDimitry Andric 870b57cec5SDimitry Andric /// LastFPdOpCycleIdx stores the numbeer returned by getCurrCycleIdx() 880b57cec5SDimitry Andric /// when a stalling operation is scheduled (which uses the FPd resource). 890b57cec5SDimitry Andric unsigned LastFPdOpCycleIdx; 900b57cec5SDimitry Andric 910b57cec5SDimitry Andric /// A counter of decoder groups scheduled. 920b57cec5SDimitry Andric unsigned GrpCount; 930b57cec5SDimitry Andric getCurrGroupSize()940b57cec5SDimitry Andric unsigned getCurrGroupSize() {return CurrGroupSize;}; 950b57cec5SDimitry Andric 960b57cec5SDimitry Andric /// Start next decoder group. 970b57cec5SDimitry Andric void nextGroup(); 980b57cec5SDimitry Andric 990b57cec5SDimitry Andric /// Clear all counters for processor resources. 1000b57cec5SDimitry Andric void clearProcResCounters(); 1010b57cec5SDimitry Andric 1020b57cec5SDimitry Andric /// With the goal of alternating processor sides for stalling (FPd) 1030b57cec5SDimitry Andric /// ops, return true if it seems good to schedule an FPd op next. 1040b57cec5SDimitry Andric bool isFPdOpPreferred_distance(SUnit *SU) const; 1050b57cec5SDimitry Andric 1060b57cec5SDimitry Andric /// Last emitted instruction or nullptr. 1070b57cec5SDimitry Andric MachineInstr *LastEmittedMI; 1080b57cec5SDimitry Andric 1090b57cec5SDimitry Andric public: SystemZHazardRecognizer(const SystemZInstrInfo * tii,const TargetSchedModel * SM)1100b57cec5SDimitry Andric SystemZHazardRecognizer(const SystemZInstrInfo *tii, 1110b57cec5SDimitry Andric const TargetSchedModel *SM) 1120b57cec5SDimitry Andric : TII(tii), SchedModel(SM) { 1130b57cec5SDimitry Andric Reset(); 1140b57cec5SDimitry Andric } 1150b57cec5SDimitry Andric 116*e8d8bef9SDimitry Andric HazardType getHazardType(SUnit *SU, int Stalls = 0) override; 1170b57cec5SDimitry Andric void Reset() override; 1180b57cec5SDimitry Andric void EmitInstruction(SUnit *SU) override; 1190b57cec5SDimitry Andric 1200b57cec5SDimitry Andric /// Resolves and cache a resolved scheduling class for an SUnit. getSchedClass(SUnit * SU)1210b57cec5SDimitry Andric const MCSchedClassDesc *getSchedClass(SUnit *SU) const { 1220b57cec5SDimitry Andric if (!SU->SchedClass && SchedModel->hasInstrSchedModel()) 1230b57cec5SDimitry Andric SU->SchedClass = SchedModel->resolveSchedClass(SU->getInstr()); 1240b57cec5SDimitry Andric return SU->SchedClass; 1250b57cec5SDimitry Andric } 1260b57cec5SDimitry Andric 1270b57cec5SDimitry Andric /// Wrap a non-scheduled instruction in an SU and emit it. 1280b57cec5SDimitry Andric void emitInstruction(MachineInstr *MI, bool TakenBranch = false); 1290b57cec5SDimitry Andric 1300b57cec5SDimitry Andric // Cost functions used by SystemZPostRASchedStrategy while 1310b57cec5SDimitry Andric // evaluating candidates. 1320b57cec5SDimitry Andric 1330b57cec5SDimitry Andric /// Return the cost of decoder grouping for SU. If SU must start a 1340b57cec5SDimitry Andric /// new decoder group, this is negative if this fits the schedule or 1350b57cec5SDimitry Andric /// positive if it would mean ending a group prematurely. For normal 1360b57cec5SDimitry Andric /// instructions this returns 0. 1370b57cec5SDimitry Andric int groupingCost(SUnit *SU) const; 1380b57cec5SDimitry Andric 1390b57cec5SDimitry Andric /// Return the cost of SU in regards to processor resources usage. 1400b57cec5SDimitry Andric /// A positive value means it would be better to wait with SU, while 1410b57cec5SDimitry Andric /// a negative value means it would be good to schedule SU next. 1420b57cec5SDimitry Andric int resourcesCost(SUnit *SU); 1430b57cec5SDimitry Andric 1440b57cec5SDimitry Andric #ifndef NDEBUG 1450b57cec5SDimitry Andric // Debug dumping. 1460b57cec5SDimitry Andric std::string CurGroupDbg; // current group as text 1470b57cec5SDimitry Andric void dumpSU(SUnit *SU, raw_ostream &OS) const; 1480b57cec5SDimitry Andric void dumpCurrGroup(std::string Msg = "") const; 1490b57cec5SDimitry Andric void dumpProcResourceCounters() const; 1500b57cec5SDimitry Andric void dumpState() const; 1510b57cec5SDimitry Andric #endif 1520b57cec5SDimitry Andric getLastEmittedMI()1530b57cec5SDimitry Andric MachineBasicBlock::iterator getLastEmittedMI() { return LastEmittedMI; } 1540b57cec5SDimitry Andric 1550b57cec5SDimitry Andric /// Copy counters from end of single predecessor. 1560b57cec5SDimitry Andric void copyState(SystemZHazardRecognizer *Incoming); 1570b57cec5SDimitry Andric }; 1580b57cec5SDimitry Andric 1590b57cec5SDimitry Andric } // namespace llvm 1600b57cec5SDimitry Andric 1610b57cec5SDimitry Andric #endif /* LLVM_LIB_TARGET_SYSTEMZ_SYSTEMZHAZARDRECOGNIZER_H */ 162