xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/SystemZ/SystemZHazardRecognizer.h (revision e8d8bef961a50d4dc22501cde4fb9fb0be1b2532)
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