MCSchedule.h 16 KB

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