xref: /freebsd-src/contrib/llvm-project/llvm/include/llvm/CodeGen/TargetSchedule.h (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
10b57cec5SDimitry Andric //===- llvm/CodeGen/TargetSchedule.h - Sched Machine Model ------*- 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 defines a wrapper around MCSchedModel that allows the interface to
100b57cec5SDimitry Andric // benefit from information currently only available in TargetInstrInfo.
110b57cec5SDimitry Andric // Ideally, the scheduling interface would be fully defined in the MC layer.
120b57cec5SDimitry Andric //
130b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
140b57cec5SDimitry Andric 
150b57cec5SDimitry Andric #ifndef LLVM_CODEGEN_TARGETSCHEDULE_H
160b57cec5SDimitry Andric #define LLVM_CODEGEN_TARGETSCHEDULE_H
170b57cec5SDimitry Andric 
180b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h"
190b57cec5SDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h"
200b57cec5SDimitry Andric #include "llvm/Config/llvm-config.h"
210b57cec5SDimitry Andric #include "llvm/MC/MCInstrItineraries.h"
220b57cec5SDimitry Andric #include "llvm/MC/MCSchedule.h"
230b57cec5SDimitry Andric 
240b57cec5SDimitry Andric namespace llvm {
250b57cec5SDimitry Andric 
260b57cec5SDimitry Andric class MachineInstr;
270b57cec5SDimitry Andric class TargetInstrInfo;
280b57cec5SDimitry Andric 
290b57cec5SDimitry Andric /// Provide an instruction scheduling machine model to CodeGen passes.
300b57cec5SDimitry Andric class TargetSchedModel {
310b57cec5SDimitry Andric   // For efficiency, hold a copy of the statically defined MCSchedModel for this
320b57cec5SDimitry Andric   // processor.
330b57cec5SDimitry Andric   MCSchedModel SchedModel;
340b57cec5SDimitry Andric   InstrItineraryData InstrItins;
350b57cec5SDimitry Andric   const TargetSubtargetInfo *STI = nullptr;
360b57cec5SDimitry Andric   const TargetInstrInfo *TII = nullptr;
370b57cec5SDimitry Andric 
380b57cec5SDimitry Andric   SmallVector<unsigned, 16> ResourceFactors;
39480093f4SDimitry Andric 
40480093f4SDimitry Andric   // Multiply to normalize microops to resource units.
41480093f4SDimitry Andric   unsigned MicroOpFactor = 0;
42480093f4SDimitry Andric 
43480093f4SDimitry Andric   // Resource units per cycle. Latency normalization factor.
44480093f4SDimitry Andric   unsigned ResourceLCM = 0;
450b57cec5SDimitry Andric 
460b57cec5SDimitry Andric   unsigned computeInstrLatency(const MCSchedClassDesc &SCDesc) const;
470b57cec5SDimitry Andric 
480b57cec5SDimitry Andric public:
TargetSchedModel()49*5f757f3fSDimitry Andric   TargetSchedModel() : SchedModel(MCSchedModel::Default) {}
500b57cec5SDimitry Andric 
510b57cec5SDimitry Andric   /// Initialize the machine model for instruction scheduling.
520b57cec5SDimitry Andric   ///
530b57cec5SDimitry Andric   /// The machine model API keeps a copy of the top-level MCSchedModel table
540b57cec5SDimitry Andric   /// indices and may query TargetSubtargetInfo and TargetInstrInfo to resolve
550b57cec5SDimitry Andric   /// dynamic properties.
560b57cec5SDimitry Andric   void init(const TargetSubtargetInfo *TSInfo);
570b57cec5SDimitry Andric 
580b57cec5SDimitry Andric   /// Return the MCSchedClassDesc for this instruction.
590b57cec5SDimitry Andric   const MCSchedClassDesc *resolveSchedClass(const MachineInstr *MI) const;
600b57cec5SDimitry Andric 
610b57cec5SDimitry Andric   /// TargetSubtargetInfo getter.
getSubtargetInfo()620b57cec5SDimitry Andric   const TargetSubtargetInfo *getSubtargetInfo() const { return STI; }
630b57cec5SDimitry Andric 
640b57cec5SDimitry Andric   /// TargetInstrInfo getter.
getInstrInfo()650b57cec5SDimitry Andric   const TargetInstrInfo *getInstrInfo() const { return TII; }
660b57cec5SDimitry Andric 
670b57cec5SDimitry Andric   /// Return true if this machine model includes an instruction-level
680b57cec5SDimitry Andric   /// scheduling model.
690b57cec5SDimitry Andric   ///
700b57cec5SDimitry Andric   /// This is more detailed than the course grain IssueWidth and default
710b57cec5SDimitry Andric   /// latency properties, but separate from the per-cycle itinerary data.
720b57cec5SDimitry Andric   bool hasInstrSchedModel() const;
730b57cec5SDimitry Andric 
getMCSchedModel()740b57cec5SDimitry Andric   const MCSchedModel *getMCSchedModel() const { return &SchedModel; }
750b57cec5SDimitry Andric 
760b57cec5SDimitry Andric   /// Return true if this machine model includes cycle-to-cycle itinerary
770b57cec5SDimitry Andric   /// data.
780b57cec5SDimitry Andric   ///
790b57cec5SDimitry Andric   /// This models scheduling at each stage in the processor pipeline.
800b57cec5SDimitry Andric   bool hasInstrItineraries() const;
810b57cec5SDimitry Andric 
getInstrItineraries()820b57cec5SDimitry Andric   const InstrItineraryData *getInstrItineraries() const {
830b57cec5SDimitry Andric     if (hasInstrItineraries())
840b57cec5SDimitry Andric       return &InstrItins;
850b57cec5SDimitry Andric     return nullptr;
860b57cec5SDimitry Andric   }
870b57cec5SDimitry Andric 
880b57cec5SDimitry Andric   /// Return true if this machine model includes an instruction-level
890b57cec5SDimitry Andric   /// scheduling model or cycle-to-cycle itinerary data.
hasInstrSchedModelOrItineraries()900b57cec5SDimitry Andric   bool hasInstrSchedModelOrItineraries() const {
910b57cec5SDimitry Andric     return hasInstrSchedModel() || hasInstrItineraries();
920b57cec5SDimitry Andric   }
93*5f757f3fSDimitry Andric   bool enableIntervals() const;
940b57cec5SDimitry Andric   /// Identify the processor corresponding to the current subtarget.
getProcessorID()950b57cec5SDimitry Andric   unsigned getProcessorID() const { return SchedModel.getProcessorID(); }
960b57cec5SDimitry Andric 
970b57cec5SDimitry Andric   /// Maximum number of micro-ops that may be scheduled per cycle.
getIssueWidth()980b57cec5SDimitry Andric   unsigned getIssueWidth() const { return SchedModel.IssueWidth; }
990b57cec5SDimitry Andric 
1000b57cec5SDimitry Andric   /// Return true if new group must begin.
1010b57cec5SDimitry Andric   bool mustBeginGroup(const MachineInstr *MI,
1020b57cec5SDimitry Andric                           const MCSchedClassDesc *SC = nullptr) const;
1030b57cec5SDimitry Andric   /// Return true if current group must end.
1040b57cec5SDimitry Andric   bool mustEndGroup(const MachineInstr *MI,
1050b57cec5SDimitry Andric                           const MCSchedClassDesc *SC = nullptr) const;
1060b57cec5SDimitry Andric 
1070b57cec5SDimitry Andric   /// Return the number of issue slots required for this MI.
1080b57cec5SDimitry Andric   unsigned getNumMicroOps(const MachineInstr *MI,
1090b57cec5SDimitry Andric                           const MCSchedClassDesc *SC = nullptr) const;
1100b57cec5SDimitry Andric 
1110b57cec5SDimitry Andric   /// Get the number of kinds of resources for this target.
getNumProcResourceKinds()1120b57cec5SDimitry Andric   unsigned getNumProcResourceKinds() const {
1130b57cec5SDimitry Andric     return SchedModel.getNumProcResourceKinds();
1140b57cec5SDimitry Andric   }
1150b57cec5SDimitry Andric 
1160b57cec5SDimitry Andric   /// Get a processor resource by ID for convenience.
getProcResource(unsigned PIdx)1170b57cec5SDimitry Andric   const MCProcResourceDesc *getProcResource(unsigned PIdx) const {
1180b57cec5SDimitry Andric     return SchedModel.getProcResource(PIdx);
1190b57cec5SDimitry Andric   }
1200b57cec5SDimitry Andric 
1210b57cec5SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
getResourceName(unsigned PIdx)1220b57cec5SDimitry Andric   const char *getResourceName(unsigned PIdx) const {
1230b57cec5SDimitry Andric     if (!PIdx)
1240b57cec5SDimitry Andric       return "MOps";
1250b57cec5SDimitry Andric     return SchedModel.getProcResource(PIdx)->Name;
1260b57cec5SDimitry Andric   }
1270b57cec5SDimitry Andric #endif
1280b57cec5SDimitry Andric 
1290b57cec5SDimitry Andric   using ProcResIter = const MCWriteProcResEntry *;
1300b57cec5SDimitry Andric 
1310b57cec5SDimitry Andric   // Get an iterator into the processor resources consumed by this
1320b57cec5SDimitry Andric   // scheduling class.
getWriteProcResBegin(const MCSchedClassDesc * SC)1330b57cec5SDimitry Andric   ProcResIter getWriteProcResBegin(const MCSchedClassDesc *SC) const {
1340b57cec5SDimitry Andric     // The subtarget holds a single resource table for all processors.
1350b57cec5SDimitry Andric     return STI->getWriteProcResBegin(SC);
1360b57cec5SDimitry Andric   }
getWriteProcResEnd(const MCSchedClassDesc * SC)1370b57cec5SDimitry Andric   ProcResIter getWriteProcResEnd(const MCSchedClassDesc *SC) const {
1380b57cec5SDimitry Andric     return STI->getWriteProcResEnd(SC);
1390b57cec5SDimitry Andric   }
1400b57cec5SDimitry Andric 
1410b57cec5SDimitry Andric   /// Multiply the number of units consumed for a resource by this factor
1420b57cec5SDimitry Andric   /// to normalize it relative to other resources.
getResourceFactor(unsigned ResIdx)1430b57cec5SDimitry Andric   unsigned getResourceFactor(unsigned ResIdx) const {
1440b57cec5SDimitry Andric     return ResourceFactors[ResIdx];
1450b57cec5SDimitry Andric   }
1460b57cec5SDimitry Andric 
1470b57cec5SDimitry Andric   /// Multiply number of micro-ops by this factor to normalize it
1480b57cec5SDimitry Andric   /// relative to other resources.
getMicroOpFactor()1490b57cec5SDimitry Andric   unsigned getMicroOpFactor() const {
1500b57cec5SDimitry Andric     return MicroOpFactor;
1510b57cec5SDimitry Andric   }
1520b57cec5SDimitry Andric 
1530b57cec5SDimitry Andric   /// Multiply cycle count by this factor to normalize it relative to
1540b57cec5SDimitry Andric   /// other resources. This is the number of resource units per cycle.
getLatencyFactor()1550b57cec5SDimitry Andric   unsigned getLatencyFactor() const {
1560b57cec5SDimitry Andric     return ResourceLCM;
1570b57cec5SDimitry Andric   }
1580b57cec5SDimitry Andric 
1590b57cec5SDimitry Andric   /// Number of micro-ops that may be buffered for OOO execution.
getMicroOpBufferSize()1600b57cec5SDimitry Andric   unsigned getMicroOpBufferSize() const { return SchedModel.MicroOpBufferSize; }
1610b57cec5SDimitry Andric 
1620b57cec5SDimitry Andric   /// Number of resource units that may be buffered for OOO execution.
1630b57cec5SDimitry Andric   /// \return The buffer size in resource units or -1 for unlimited.
getResourceBufferSize(unsigned PIdx)1640b57cec5SDimitry Andric   int getResourceBufferSize(unsigned PIdx) const {
1650b57cec5SDimitry Andric     return SchedModel.getProcResource(PIdx)->BufferSize;
1660b57cec5SDimitry Andric   }
1670b57cec5SDimitry Andric 
1680b57cec5SDimitry Andric   /// Compute operand latency based on the available machine model.
1690b57cec5SDimitry Andric   ///
1700b57cec5SDimitry Andric   /// Compute and return the latency of the given data dependent def and use
1710b57cec5SDimitry Andric   /// when the operand indices are already known. UseMI may be NULL for an
1720b57cec5SDimitry Andric   /// unknown user.
1730b57cec5SDimitry Andric   unsigned computeOperandLatency(const MachineInstr *DefMI, unsigned DefOperIdx,
1740b57cec5SDimitry Andric                                  const MachineInstr *UseMI, unsigned UseOperIdx)
1750b57cec5SDimitry Andric     const;
1760b57cec5SDimitry Andric 
1770b57cec5SDimitry Andric   /// Compute the instruction latency based on the available machine
1780b57cec5SDimitry Andric   /// model.
1790b57cec5SDimitry Andric   ///
1800b57cec5SDimitry Andric   /// Compute and return the expected latency of this instruction independent of
1810b57cec5SDimitry Andric   /// a particular use. computeOperandLatency is the preferred API, but this is
1820b57cec5SDimitry Andric   /// occasionally useful to help estimate instruction cost.
1830b57cec5SDimitry Andric   ///
1840b57cec5SDimitry Andric   /// If UseDefaultDefLatency is false and no new machine sched model is
1850b57cec5SDimitry Andric   /// present this method falls back to TII->getInstrLatency with an empty
1860b57cec5SDimitry Andric   /// instruction itinerary (this is so we preserve the previous behavior of the
1870b57cec5SDimitry Andric   /// if converter after moving it to TargetSchedModel).
1880b57cec5SDimitry Andric   unsigned computeInstrLatency(const MachineInstr *MI,
1890b57cec5SDimitry Andric                                bool UseDefaultDefLatency = true) const;
1900b57cec5SDimitry Andric   unsigned computeInstrLatency(const MCInst &Inst) const;
1910b57cec5SDimitry Andric   unsigned computeInstrLatency(unsigned Opcode) const;
1920b57cec5SDimitry Andric 
1930b57cec5SDimitry Andric 
1940b57cec5SDimitry Andric   /// Output dependency latency of a pair of defs of the same register.
1950b57cec5SDimitry Andric   ///
1960b57cec5SDimitry Andric   /// This is typically one cycle.
1970b57cec5SDimitry Andric   unsigned computeOutputLatency(const MachineInstr *DefMI, unsigned DefOperIdx,
1980b57cec5SDimitry Andric                                 const MachineInstr *DepMI) const;
1990b57cec5SDimitry Andric 
2000b57cec5SDimitry Andric   /// Compute the reciprocal throughput of the given instruction.
2010b57cec5SDimitry Andric   double computeReciprocalThroughput(const MachineInstr *MI) const;
2020b57cec5SDimitry Andric   double computeReciprocalThroughput(const MCInst &MI) const;
2030b57cec5SDimitry Andric   double computeReciprocalThroughput(unsigned Opcode) const;
2040b57cec5SDimitry Andric };
2050b57cec5SDimitry Andric 
2060b57cec5SDimitry Andric } // end namespace llvm
2070b57cec5SDimitry Andric 
2080b57cec5SDimitry Andric #endif // LLVM_CODEGEN_TARGETSCHEDULE_H
209