MCSchedule.h 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. //===-- llvm/MC/MCSchedule.h - Scheduling -----------------------*- C++ -*-===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. //
  9. // This file defines the classes used to describe a subtarget's machine model
  10. // for scheduling and other instruction cost heuristics.
  11. //
  12. //===----------------------------------------------------------------------===//
  13. #ifndef LLVM_MC_MCSCHEDULE_H
  14. #define LLVM_MC_MCSCHEDULE_H
  15. #include "llvm/ADT/Optional.h"
  16. #include "llvm/Config/llvm-config.h"
  17. #include "llvm/Support/DataTypes.h"
  18. #include <cassert>
  19. namespace llvm {
  20. template <typename T> class ArrayRef;
  21. struct InstrItinerary;
  22. class MCSubtargetInfo;
  23. class MCInstrInfo;
  24. class MCInst;
  25. class InstrItineraryData;
  26. /// Define a kind of processor resource that will be modeled by the scheduler.
  27. struct MCProcResourceDesc {
  28. const char *Name;
  29. unsigned NumUnits; // Number of resource of this kind
  30. unsigned SuperIdx; // Index of the resources kind that contains this kind.
  31. // Number of resources that may be buffered.
  32. //
  33. // Buffered resources (BufferSize != 0) may be consumed at some indeterminate
  34. // cycle after dispatch. This should be used for out-of-order cpus when
  35. // instructions that use this resource can be buffered in a reservaton
  36. // station.
  37. //
  38. // Unbuffered resources (BufferSize == 0) always consume their resource some
  39. // fixed number of cycles after dispatch. If a resource is unbuffered, then
  40. // the scheduler will avoid scheduling instructions with conflicting resources
  41. // in the same cycle. This is for in-order cpus, or the in-order portion of
  42. // an out-of-order cpus.
  43. int BufferSize;
  44. // If the resource has sub-units, a pointer to the first element of an array
  45. // of `NumUnits` elements containing the ProcResourceIdx of the sub units.
  46. // nullptr if the resource does not have sub-units.
  47. const unsigned *SubUnitsIdxBegin;
  48. bool operator==(const MCProcResourceDesc &Other) const {
  49. return NumUnits == Other.NumUnits && SuperIdx == Other.SuperIdx
  50. && BufferSize == Other.BufferSize;
  51. }
  52. };
  53. /// Identify one of the processor resource kinds consumed by a particular
  54. /// scheduling class for the specified number of cycles.
  55. struct MCWriteProcResEntry {
  56. uint16_t ProcResourceIdx;
  57. uint16_t Cycles;
  58. bool operator==(const MCWriteProcResEntry &Other) const {
  59. return ProcResourceIdx == Other.ProcResourceIdx && Cycles == Other.Cycles;
  60. }
  61. };
  62. /// Specify the latency in cpu cycles for a particular scheduling class and def
  63. /// index. -1 indicates an invalid latency. Heuristics would typically consider
  64. /// an instruction with invalid latency to have infinite latency. Also identify
  65. /// the WriteResources of this def. When the operand expands to a sequence of
  66. /// writes, this ID is the last write in the sequence.
  67. struct MCWriteLatencyEntry {
  68. int16_t Cycles;
  69. uint16_t WriteResourceID;
  70. bool operator==(const MCWriteLatencyEntry &Other) const {
  71. return Cycles == Other.Cycles && WriteResourceID == Other.WriteResourceID;
  72. }
  73. };
  74. /// Specify the number of cycles allowed after instruction issue before a
  75. /// particular use operand reads its registers. This effectively reduces the
  76. /// write's latency. Here we allow negative cycles for corner cases where
  77. /// latency increases. This rule only applies when the entry's WriteResource
  78. /// matches the write's WriteResource.
  79. ///
  80. /// MCReadAdvanceEntries are sorted first by operand index (UseIdx), then by
  81. /// WriteResourceIdx.
  82. struct MCReadAdvanceEntry {
  83. unsigned UseIdx;
  84. unsigned WriteResourceID;
  85. int Cycles;
  86. bool operator==(const MCReadAdvanceEntry &Other) const {
  87. return UseIdx == Other.UseIdx && WriteResourceID == Other.WriteResourceID
  88. && Cycles == Other.Cycles;
  89. }
  90. };
  91. /// Summarize the scheduling resources required for an instruction of a
  92. /// particular scheduling class.
  93. ///
  94. /// Defined as an aggregate struct for creating tables with initializer lists.
  95. struct MCSchedClassDesc {
  96. static const unsigned short InvalidNumMicroOps = (1U << 13) - 1;
  97. static const unsigned short VariantNumMicroOps = InvalidNumMicroOps - 1;
  98. #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
  99. const char* Name;
  100. #endif
  101. uint16_t NumMicroOps : 13;
  102. uint16_t BeginGroup : 1;
  103. uint16_t EndGroup : 1;
  104. uint16_t RetireOOO : 1;
  105. uint16_t WriteProcResIdx; // First index into WriteProcResTable.
  106. uint16_t NumWriteProcResEntries;
  107. uint16_t WriteLatencyIdx; // First index into WriteLatencyTable.
  108. uint16_t NumWriteLatencyEntries;
  109. uint16_t ReadAdvanceIdx; // First index into ReadAdvanceTable.
  110. uint16_t NumReadAdvanceEntries;
  111. bool isValid() const {
  112. return NumMicroOps != InvalidNumMicroOps;
  113. }
  114. bool isVariant() const {
  115. return NumMicroOps == VariantNumMicroOps;
  116. }
  117. };
  118. /// Specify the cost of a register definition in terms of number of physical
  119. /// register allocated at register renaming stage. For example, AMD Jaguar.
  120. /// natively supports 128-bit data types, and operations on 256-bit registers
  121. /// (i.e. YMM registers) are internally split into two COPs (complex operations)
  122. /// and each COP updates a physical register. Basically, on Jaguar, a YMM
  123. /// register write effectively consumes two physical registers. That means,
  124. /// the cost of a YMM write in the BtVer2 model is 2.
  125. struct MCRegisterCostEntry {
  126. unsigned RegisterClassID;
  127. unsigned Cost;
  128. bool AllowMoveElimination;
  129. };
  130. /// A register file descriptor.
  131. ///
  132. /// This struct allows to describe processor register files. In particular, it
  133. /// helps describing the size of the register file, as well as the cost of
  134. /// allocating a register file at register renaming stage.
  135. /// FIXME: this struct can be extended to provide information about the number
  136. /// of read/write ports to the register file. A value of zero for field
  137. /// 'NumPhysRegs' means: this register file has an unbounded number of physical
  138. /// registers.
  139. struct MCRegisterFileDesc {
  140. const char *Name;
  141. uint16_t NumPhysRegs;
  142. uint16_t NumRegisterCostEntries;
  143. // Index of the first cost entry in MCExtraProcessorInfo::RegisterCostTable.
  144. uint16_t RegisterCostEntryIdx;
  145. // A value of zero means: there is no limit in the number of moves that can be
  146. // eliminated every cycle.
  147. uint16_t MaxMovesEliminatedPerCycle;
  148. // Ture if this register file only knows how to optimize register moves from
  149. // known zero registers.
  150. bool AllowZeroMoveEliminationOnly;
  151. };
  152. /// Provide extra details about the machine processor.
  153. ///
  154. /// This is a collection of "optional" processor information that is not
  155. /// normally used by the LLVM machine schedulers, but that can be consumed by
  156. /// external tools like llvm-mca to improve the quality of the peformance
  157. /// analysis.
  158. struct MCExtraProcessorInfo {
  159. // Actual size of the reorder buffer in hardware.
  160. unsigned ReorderBufferSize;
  161. // Number of instructions retired per cycle.
  162. unsigned MaxRetirePerCycle;
  163. const MCRegisterFileDesc *RegisterFiles;
  164. unsigned NumRegisterFiles;
  165. const MCRegisterCostEntry *RegisterCostTable;
  166. unsigned NumRegisterCostEntries;
  167. unsigned LoadQueueID;
  168. unsigned StoreQueueID;
  169. };
  170. /// Machine model for scheduling, bundling, and heuristics.
  171. ///
  172. /// The machine model directly provides basic information about the
  173. /// microarchitecture to the scheduler in the form of properties. It also
  174. /// optionally refers to scheduler resource tables and itinerary
  175. /// tables. Scheduler resource tables model the latency and cost for each
  176. /// instruction type. Itinerary tables are an independent mechanism that
  177. /// provides a detailed reservation table describing each cycle of instruction
  178. /// execution. Subtargets may define any or all of the above categories of data
  179. /// depending on the type of CPU and selected scheduler.
  180. ///
  181. /// The machine independent properties defined here are used by the scheduler as
  182. /// an abstract machine model. A real micro-architecture has a number of
  183. /// buffers, queues, and stages. Declaring that a given machine-independent
  184. /// abstract property corresponds to a specific physical property across all
  185. /// subtargets can't be done. Nonetheless, the abstract model is
  186. /// useful. Futhermore, subtargets typically extend this model with processor
  187. /// specific resources to model any hardware features that can be exploited by
  188. /// scheduling heuristics and aren't sufficiently represented in the abstract.
  189. ///
  190. /// The abstract pipeline is built around the notion of an "issue point". This
  191. /// is merely a reference point for counting machine cycles. The physical
  192. /// machine will have pipeline stages that delay execution. The scheduler does
  193. /// not model those delays because they are irrelevant as long as they are
  194. /// consistent. Inaccuracies arise when instructions have different execution
  195. /// delays relative to each other, in addition to their intrinsic latency. Those
  196. /// special cases can be handled by TableGen constructs such as, ReadAdvance,
  197. /// which reduces latency when reading data, and ResourceCycles, which consumes
  198. /// a processor resource when writing data for a number of abstract
  199. /// cycles.
  200. ///
  201. /// TODO: One tool currently missing is the ability to add a delay to
  202. /// ResourceCycles. That would be easy to add and would likely cover all cases
  203. /// currently handled by the legacy itinerary tables.
  204. ///
  205. /// A note on out-of-order execution and, more generally, instruction
  206. /// buffers. Part of the CPU pipeline is always in-order. The issue point, which
  207. /// is the point of reference for counting cycles, only makes sense as an
  208. /// in-order part of the pipeline. Other parts of the pipeline are sometimes
  209. /// falling behind and sometimes catching up. It's only interesting to model
  210. /// those other, decoupled parts of the pipeline if they may be predictably
  211. /// resource constrained in a way that the scheduler can exploit.
  212. ///
  213. /// The LLVM machine model distinguishes between in-order constraints and
  214. /// out-of-order constraints so that the target's scheduling strategy can apply
  215. /// appropriate heuristics. For a well-balanced CPU pipeline, out-of-order
  216. /// resources would not typically be treated as a hard scheduling
  217. /// constraint. For example, in the GenericScheduler, a delay caused by limited
  218. /// out-of-order resources is not directly reflected in the number of cycles
  219. /// that the scheduler sees between issuing an instruction and its dependent
  220. /// instructions. In other words, out-of-order resources don't directly increase
  221. /// the latency between pairs of instructions. However, they can still be used
  222. /// to detect potential bottlenecks across a sequence of instructions and bias
  223. /// the scheduling heuristics appropriately.
  224. struct MCSchedModel {
  225. // IssueWidth is the maximum number of instructions that may be scheduled in
  226. // the same per-cycle group. This is meant to be a hard in-order constraint
  227. // (a.k.a. "hazard"). In the GenericScheduler strategy, no more than
  228. // IssueWidth micro-ops can ever be scheduled in a particular cycle.
  229. //
  230. // In practice, IssueWidth is useful to model any bottleneck between the
  231. // decoder (after micro-op expansion) and the out-of-order reservation
  232. // stations or the decoder bandwidth itself. If the total number of
  233. // reservation stations is also a bottleneck, or if any other pipeline stage
  234. // has a bandwidth limitation, then that can be naturally modeled by adding an
  235. // out-of-order processor resource.
  236. unsigned IssueWidth;
  237. static const unsigned DefaultIssueWidth = 1;
  238. // MicroOpBufferSize is the number of micro-ops that the processor may buffer
  239. // for out-of-order execution.
  240. //
  241. // "0" means operations that are not ready in this cycle are not considered
  242. // for scheduling (they go in the pending queue). Latency is paramount. This
  243. // may be more efficient if many instructions are pending in a schedule.
  244. //
  245. // "1" means all instructions are considered for scheduling regardless of
  246. // whether they are ready in this cycle. Latency still causes issue stalls,
  247. // but we balance those stalls against other heuristics.
  248. //
  249. // "> 1" means the processor is out-of-order. This is a machine independent
  250. // estimate of highly machine specific characteristics such as the register
  251. // renaming pool and reorder buffer.
  252. unsigned MicroOpBufferSize;
  253. static const unsigned DefaultMicroOpBufferSize = 0;
  254. // LoopMicroOpBufferSize is the number of micro-ops that the processor may
  255. // buffer for optimized loop execution. More generally, this represents the
  256. // optimal number of micro-ops in a loop body. A loop may be partially
  257. // unrolled to bring the count of micro-ops in the loop body closer to this
  258. // number.
  259. unsigned LoopMicroOpBufferSize;
  260. static const unsigned DefaultLoopMicroOpBufferSize = 0;
  261. // LoadLatency is the expected latency of load instructions.
  262. unsigned LoadLatency;
  263. static const unsigned DefaultLoadLatency = 4;
  264. // HighLatency is the expected latency of "very high latency" operations.
  265. // See TargetInstrInfo::isHighLatencyDef().
  266. // By default, this is set to an arbitrarily high number of cycles
  267. // likely to have some impact on scheduling heuristics.
  268. unsigned HighLatency;
  269. static const unsigned DefaultHighLatency = 10;
  270. // MispredictPenalty is the typical number of extra cycles the processor
  271. // takes to recover from a branch misprediction.
  272. unsigned MispredictPenalty;
  273. static const unsigned DefaultMispredictPenalty = 10;
  274. bool PostRAScheduler; // default value is false
  275. bool CompleteModel;
  276. unsigned ProcID;
  277. const MCProcResourceDesc *ProcResourceTable;
  278. const MCSchedClassDesc *SchedClassTable;
  279. unsigned NumProcResourceKinds;
  280. unsigned NumSchedClasses;
  281. // Instruction itinerary tables used by InstrItineraryData.
  282. friend class InstrItineraryData;
  283. const InstrItinerary *InstrItineraries;
  284. const MCExtraProcessorInfo *ExtraProcessorInfo;
  285. bool hasExtraProcessorInfo() const { return ExtraProcessorInfo; }
  286. unsigned getProcessorID() const { return ProcID; }
  287. /// Does this machine model include instruction-level scheduling.
  288. bool hasInstrSchedModel() const { return SchedClassTable; }
  289. const MCExtraProcessorInfo &getExtraProcessorInfo() const {
  290. assert(hasExtraProcessorInfo() &&
  291. "No extra information available for this model");
  292. return *ExtraProcessorInfo;
  293. }
  294. /// Return true if this machine model data for all instructions with a
  295. /// scheduling class (itinerary class or SchedRW list).
  296. bool isComplete() const { return CompleteModel; }
  297. /// Return true if machine supports out of order execution.
  298. bool isOutOfOrder() const { return MicroOpBufferSize > 1; }
  299. unsigned getNumProcResourceKinds() const {
  300. return NumProcResourceKinds;
  301. }
  302. const MCProcResourceDesc *getProcResource(unsigned ProcResourceIdx) const {
  303. assert(hasInstrSchedModel() && "No scheduling machine model");
  304. assert(ProcResourceIdx < NumProcResourceKinds && "bad proc resource idx");
  305. return &ProcResourceTable[ProcResourceIdx];
  306. }
  307. const MCSchedClassDesc *getSchedClassDesc(unsigned SchedClassIdx) const {
  308. assert(hasInstrSchedModel() && "No scheduling machine model");
  309. assert(SchedClassIdx < NumSchedClasses && "bad scheduling class idx");
  310. return &SchedClassTable[SchedClassIdx];
  311. }
  312. /// Returns the latency value for the scheduling class.
  313. static int computeInstrLatency(const MCSubtargetInfo &STI,
  314. const MCSchedClassDesc &SCDesc);
  315. int computeInstrLatency(const MCSubtargetInfo &STI, unsigned SClass) const;
  316. int computeInstrLatency(const MCSubtargetInfo &STI, const MCInstrInfo &MCII,
  317. const MCInst &Inst) const;
  318. // Returns the reciprocal throughput information from a MCSchedClassDesc.
  319. static double
  320. getReciprocalThroughput(const MCSubtargetInfo &STI,
  321. const MCSchedClassDesc &SCDesc);
  322. static double
  323. getReciprocalThroughput(unsigned SchedClass, const InstrItineraryData &IID);
  324. double
  325. getReciprocalThroughput(const MCSubtargetInfo &STI, const MCInstrInfo &MCII,
  326. const MCInst &Inst) const;
  327. /// Returns the maximum forwarding delay for register reads dependent on
  328. /// writes of scheduling class WriteResourceIdx.
  329. static unsigned getForwardingDelayCycles(ArrayRef<MCReadAdvanceEntry> Entries,
  330. unsigned WriteResourceIdx = 0);
  331. /// Returns the default initialized model.
  332. static const MCSchedModel &GetDefaultSchedModel() { return Default; }
  333. static const MCSchedModel Default;
  334. };
  335. } // namespace llvm
  336. #endif