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