LLVM 24.0.0git
AMDGPUCoExecSchedStrategy.cpp
Go to the documentation of this file.
1//===- AMDGPUCoExecSchedStrategy.cpp - CoExec Scheduling Strategy ---------===//
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/// \file
10/// Coexecution-focused scheduling strategy for AMDGPU.
11//
12//===----------------------------------------------------------------------===//
13
16#include "AMDGPUIGroupLP.h"
17#include "GCNHazardRecognizer.h"
18#include "llvm/Support/Debug.h"
19
20using namespace llvm;
21using namespace llvm::AMDGPU;
22
23#define DEBUG_TYPE "machine-scheduler"
24namespace {
25enum class CarriedLatency { Off, Fence, All };
26} // namespace
27
29 "amdgpu-block-carried-latency", cl::Hidden, cl::init(CarriedLatency::Off),
30 cl::desc("Estimate block-carried latency and include it in the effective "
31 "candidate stall cost."),
33 clEnumValN(CarriedLatency::Off, "off",
34 "Disabled - do not pad latency."),
35 clEnumValN(CarriedLatency::Fence, "fence",
36 "Only pad latency for memory fence (e.g. those surrounding "
37 "barrier_signal/wait)."),
39 CarriedLatency::All, "all",
40 "Pad latency for any SU with an incoming ds_load dependency.")));
41
42// Default VGPR threshold percent for coexec scheduler.
43static constexpr unsigned DefaultCoExecVGPRThresholdPercent = 100;
44
45namespace {
46
47// Used to disable post-RA scheduling with function level granularity.
48class GCNNoopPostScheduleDAG final : public ScheduleDAGInstrs {
49public:
50 explicit GCNNoopPostScheduleDAG(MachineSchedContext *C)
51 : ScheduleDAGInstrs(*C->MF, C->MLI, /*RemoveKillFlags=*/true) {}
52
53 // Do nothing.
54 void schedule() override {}
55};
56
57} // namespace
58
60 // pickOnlyChoice() releases pending instructions and checks for new hazards.
61 SUnit *OnlyChoice = Zone.pickOnlyChoice();
62 if (!Zone.Pending.empty())
63 return nullptr;
64
65 return OnlyChoice;
66}
67
68/// Apply \p ExtraBits to every slot in \p Info starting with \p StartIndex
69/// Used by MFMA co-exec rules, because MFMA co-exec slots are incremental, i.e.
70/// for every slot N it supports all instructions which were supported by the
71/// previous slot N-1 and may support something extra.
74 unsigned StartIndex) {
75 for (unsigned Index = StartIndex; Index < Info.TotalWindow; ++Index)
76 Info.Slots[Index].Mask |= ExtraBits;
77}
78
79/// Get co-execution info for a gfx950 MFMA instruction.
80/// The occupancy (cycles until the next MFMA may issue) is expressed as the
81/// first stage carrying the WMMA bit.
83 using namespace llvm;
84 using namespace llvm::AMDGPU;
85 CoExecInfo Res;
86 for (unsigned I = 0; I < MaxCoExecStages; ++I)
88
89 // TODO: Implement proper patterns support (for debugging purposes).
90 // Existing pattern letters are WMMA-specific and will probably be confusing
91 // if used as-is for MFMA. Inventing new MFMA-specific letters is an option,
92 // but perhaps the pattern should be instead dynamically reconstructed when
93 // needed by printing specific slots in full instead of a key for them.
94 Res.Pattern = "undefinedundefinedundefinedundefined";
95
96 switch (Opcode) {
97 // 4-cycle occupancy, 8-cycle window.
98 case V_MFMA_F32_16X16X128_F8F6F4_f4_f4_e64:
99 case V_MFMA_F32_16X16X128_F8F6F4_f4_f4_vgprcd_e64:
100 case V_MFMA_F32_16X16X128_F8F6F4_f4_f4_gfx940_acd:
101 case V_MFMA_F32_16X16X128_F8F6F4_f4_f4_gfx940_vcd:
102 case V_MFMA_F32_16X16X128_F8F6F4_f4_f6_e64:
103 case V_MFMA_F32_16X16X128_F8F6F4_f4_f6_vgprcd_e64:
104 case V_MFMA_F32_16X16X128_F8F6F4_f4_f6_gfx940_acd:
105 case V_MFMA_F32_16X16X128_F8F6F4_f4_f6_gfx940_vcd:
106 case V_MFMA_F32_16X16X128_F8F6F4_f6_f4_e64:
107 case V_MFMA_F32_16X16X128_F8F6F4_f6_f4_vgprcd_e64:
108 case V_MFMA_F32_16X16X128_F8F6F4_f6_f4_gfx940_acd:
109 case V_MFMA_F32_16X16X128_F8F6F4_f6_f4_gfx940_vcd:
110 case V_MFMA_F32_16X16X128_F8F6F4_f6_f6_e64:
111 case V_MFMA_F32_16X16X128_F8F6F4_f6_f6_vgprcd_e64:
112 case V_MFMA_F32_16X16X128_F8F6F4_f6_f6_gfx940_acd:
113 case V_MFMA_F32_16X16X128_F8F6F4_f6_f6_gfx940_vcd:
114 case V_MFMA_F32_16X16X32_BF16_e64:
115 case V_MFMA_F32_16X16X32_BF16_vgprcd_e64:
116 case V_MFMA_F32_16X16X32_BF16_gfx940_acd:
117 case V_MFMA_F32_16X16X32_BF16_gfx940_vcd:
118 case V_MFMA_I32_16X16X64_I8_e64:
119 case V_MFMA_I32_16X16X64_I8_vgprcd_e64:
120 case V_MFMA_I32_16X16X64_I8_gfx940_acd:
121 case V_MFMA_I32_16X16X64_I8_gfx940_vcd:
122 case V_MFMA_F32_16X16X32_F16_e64:
123 case V_MFMA_F32_16X16X32_F16_vgprcd_e64:
124 case V_MFMA_F32_16X16X32_F16_gfx940_acd:
125 case V_MFMA_F32_16X16X32_F16_gfx940_vcd:
126 case V_MFMA_SCALE_F32_16X16X128_F8F6F4_f4_f4_e64:
127 case V_MFMA_SCALE_F32_16X16X128_F8F6F4_f4_f4_vgprcd_e64:
128 case V_MFMA_SCALE_F32_16X16X128_F8F6F4_f4_f4_gfx940_acd:
129 case V_MFMA_SCALE_F32_16X16X128_F8F6F4_f4_f4_gfx940_vcd:
130 case V_MFMA_SCALE_F32_16X16X128_F8F6F4_f4_f6_e64:
131 case V_MFMA_SCALE_F32_16X16X128_F8F6F4_f4_f6_vgprcd_e64:
132 case V_MFMA_SCALE_F32_16X16X128_F8F6F4_f4_f6_gfx940_acd:
133 case V_MFMA_SCALE_F32_16X16X128_F8F6F4_f4_f6_gfx940_vcd:
134 case V_MFMA_SCALE_F32_16X16X128_F8F6F4_f6_f4_e64:
135 case V_MFMA_SCALE_F32_16X16X128_F8F6F4_f6_f4_vgprcd_e64:
136 case V_MFMA_SCALE_F32_16X16X128_F8F6F4_f6_f4_gfx940_acd:
137 case V_MFMA_SCALE_F32_16X16X128_F8F6F4_f6_f4_gfx940_vcd:
138 case V_MFMA_SCALE_F32_16X16X128_F8F6F4_f6_f6_e64:
139 case V_MFMA_SCALE_F32_16X16X128_F8F6F4_f6_f6_vgprcd_e64:
140 case V_MFMA_SCALE_F32_16X16X128_F8F6F4_f6_f6_gfx940_acd:
141 case V_MFMA_SCALE_F32_16X16X128_F8F6F4_f6_f6_gfx940_vcd:
142 // GFX9 Shader Programming Guide lists those SMFMAC separately, but for
143 // intended purposes here all those instructions are the same. This comment
144 // is to simplify reverse mapping to the SPG.
145 case V_SMFMAC_F32_16X16X64_BF16_e64:
146 case V_SMFMAC_F32_16X16X64_BF16_gfx940:
147 case V_SMFMAC_I32_16X16X128_I8_e64:
148 case V_SMFMAC_I32_16X16X128_I8_gfx940:
149 case V_SMFMAC_F32_16X16X128_BF8_BF8_e64:
150 case V_SMFMAC_F32_16X16X128_BF8_BF8_gfx940:
151 case V_SMFMAC_F32_16X16X128_BF8_FP8_e64:
152 case V_SMFMAC_F32_16X16X128_BF8_FP8_gfx940:
153 case V_SMFMAC_F32_16X16X128_FP8_BF8_e64:
154 case V_SMFMAC_F32_16X16X128_FP8_BF8_gfx940:
155 case V_SMFMAC_F32_16X16X128_FP8_FP8_e64:
156 case V_SMFMAC_F32_16X16X128_FP8_FP8_gfx940:
157 case V_SMFMAC_F32_16X16X64_F16_e64:
158 case V_SMFMAC_F32_16X16X64_F16_gfx940:
159 Res.TotalWindow = 8;
163 return Res;
164
165 // 8-cycle occupancy, 12-cycle window.
166 case V_MFMA_F32_16X16X128_F8F6F4_f4_f8_e64:
167 case V_MFMA_F32_16X16X128_F8F6F4_f4_f8_vgprcd_e64:
168 case V_MFMA_F32_16X16X128_F8F6F4_f4_f8_gfx940_acd:
169 case V_MFMA_F32_16X16X128_F8F6F4_f4_f8_gfx940_vcd:
170 case V_MFMA_F32_16X16X128_F8F6F4_f6_f8_e64:
171 case V_MFMA_F32_16X16X128_F8F6F4_f6_f8_vgprcd_e64:
172 case V_MFMA_F32_16X16X128_F8F6F4_f6_f8_gfx940_acd:
173 case V_MFMA_F32_16X16X128_F8F6F4_f6_f8_gfx940_vcd:
174 case V_MFMA_F32_16X16X128_F8F6F4_f8_f4_e64:
175 case V_MFMA_F32_16X16X128_F8F6F4_f8_f4_vgprcd_e64:
176 case V_MFMA_F32_16X16X128_F8F6F4_f8_f4_gfx940_acd:
177 case V_MFMA_F32_16X16X128_F8F6F4_f8_f4_gfx940_vcd:
178 case V_MFMA_F32_16X16X128_F8F6F4_f8_f6_e64:
179 case V_MFMA_F32_16X16X128_F8F6F4_f8_f6_vgprcd_e64:
180 case V_MFMA_F32_16X16X128_F8F6F4_f8_f6_gfx940_acd:
181 case V_MFMA_F32_16X16X128_F8F6F4_f8_f6_gfx940_vcd:
182 case V_MFMA_F32_16X16X128_F8F6F4_f8_f8_e64:
183 case V_MFMA_F32_16X16X128_F8F6F4_f8_f8_vgprcd_e64:
184 case V_MFMA_F32_16X16X128_F8F6F4_f8_f8_gfx940_acd:
185 case V_MFMA_F32_16X16X128_F8F6F4_f8_f8_gfx940_vcd:
186 case V_MFMA_SCALE_F32_16X16X128_F8F6F4_f4_f8_e64:
187 case V_MFMA_SCALE_F32_16X16X128_F8F6F4_f4_f8_vgprcd_e64:
188 case V_MFMA_SCALE_F32_16X16X128_F8F6F4_f4_f8_gfx940_acd:
189 case V_MFMA_SCALE_F32_16X16X128_F8F6F4_f4_f8_gfx940_vcd:
190 case V_MFMA_SCALE_F32_16X16X128_F8F6F4_f6_f8_e64:
191 case V_MFMA_SCALE_F32_16X16X128_F8F6F4_f6_f8_vgprcd_e64:
192 case V_MFMA_SCALE_F32_16X16X128_F8F6F4_f6_f8_gfx940_acd:
193 case V_MFMA_SCALE_F32_16X16X128_F8F6F4_f6_f8_gfx940_vcd:
194 case V_MFMA_SCALE_F32_16X16X128_F8F6F4_f8_f4_e64:
195 case V_MFMA_SCALE_F32_16X16X128_F8F6F4_f8_f4_vgprcd_e64:
196 case V_MFMA_SCALE_F32_16X16X128_F8F6F4_f8_f4_gfx940_acd:
197 case V_MFMA_SCALE_F32_16X16X128_F8F6F4_f8_f4_gfx940_vcd:
198 case V_MFMA_SCALE_F32_16X16X128_F8F6F4_f8_f6_e64:
199 case V_MFMA_SCALE_F32_16X16X128_F8F6F4_f8_f6_vgprcd_e64:
200 case V_MFMA_SCALE_F32_16X16X128_F8F6F4_f8_f6_gfx940_acd:
201 case V_MFMA_SCALE_F32_16X16X128_F8F6F4_f8_f6_gfx940_vcd:
202 case V_MFMA_SCALE_F32_16X16X128_F8F6F4_f8_f8_e64:
203 case V_MFMA_SCALE_F32_16X16X128_F8F6F4_f8_f8_vgprcd_e64:
204 case V_MFMA_SCALE_F32_16X16X128_F8F6F4_f8_f8_gfx940_acd:
205 case V_MFMA_SCALE_F32_16X16X128_F8F6F4_f8_f8_gfx940_vcd:
206 Res.TotalWindow = 12;
211 return Res;
212
213 // 4-cycle occupancy, 8-cycle window.
214 case V_MFMA_F32_32X32X64_F8F6F4_f4_f4_e64:
215 case V_MFMA_F32_32X32X64_F8F6F4_f4_f4_mac_e64:
216 case V_MFMA_F32_32X32X64_F8F6F4_f4_f4_mac_vgprcd_e64:
217 case V_MFMA_F32_32X32X64_F8F6F4_f4_f4_vgprcd_e64:
218 case V_MFMA_F32_32X32X64_F8F6F4_f4_f4_gfx940_acd:
219 case V_MFMA_F32_32X32X64_F8F6F4_f4_f4_gfx940_vcd:
220 case V_MFMA_F32_32X32X64_F8F6F4_f4_f6_e64:
221 case V_MFMA_F32_32X32X64_F8F6F4_f4_f6_mac_e64:
222 case V_MFMA_F32_32X32X64_F8F6F4_f4_f6_mac_vgprcd_e64:
223 case V_MFMA_F32_32X32X64_F8F6F4_f4_f6_vgprcd_e64:
224 case V_MFMA_F32_32X32X64_F8F6F4_f4_f6_gfx940_acd:
225 case V_MFMA_F32_32X32X64_F8F6F4_f4_f6_gfx940_vcd:
226 case V_MFMA_F32_32X32X64_F8F6F4_f6_f4_e64:
227 case V_MFMA_F32_32X32X64_F8F6F4_f6_f4_mac_e64:
228 case V_MFMA_F32_32X32X64_F8F6F4_f6_f4_mac_vgprcd_e64:
229 case V_MFMA_F32_32X32X64_F8F6F4_f6_f4_vgprcd_e64:
230 case V_MFMA_F32_32X32X64_F8F6F4_f6_f4_gfx940_acd:
231 case V_MFMA_F32_32X32X64_F8F6F4_f6_f4_gfx940_vcd:
232 case V_MFMA_F32_32X32X64_F8F6F4_f6_f6_e64:
233 case V_MFMA_F32_32X32X64_F8F6F4_f6_f6_mac_e64:
234 case V_MFMA_F32_32X32X64_F8F6F4_f6_f6_mac_vgprcd_e64:
235 case V_MFMA_F32_32X32X64_F8F6F4_f6_f6_vgprcd_e64:
236 case V_MFMA_F32_32X32X64_F8F6F4_f6_f6_gfx940_acd:
237 case V_MFMA_F32_32X32X64_F8F6F4_f6_f6_gfx940_vcd:
238 case V_MFMA_F32_32X32X16_BF16_e64:
239 case V_MFMA_F32_32X32X16_BF16_mac_e64:
240 case V_MFMA_F32_32X32X16_BF16_mac_vgprcd_e64:
241 case V_MFMA_F32_32X32X16_BF16_vgprcd_e64:
242 case V_MFMA_F32_32X32X16_BF16_gfx940_acd:
243 case V_MFMA_F32_32X32X16_BF16_gfx940_vcd:
244 case V_MFMA_I32_32X32X32_I8_e64:
245 case V_MFMA_I32_32X32X32_I8_mac_e64:
246 case V_MFMA_I32_32X32X32_I8_mac_vgprcd_e64:
247 case V_MFMA_I32_32X32X32_I8_vgprcd_e64:
248 case V_MFMA_I32_32X32X32_I8_gfx940_acd:
249 case V_MFMA_I32_32X32X32_I8_gfx940_vcd:
250 case V_MFMA_F32_32X32X16_F16_e64:
251 case V_MFMA_F32_32X32X16_F16_mac_e64:
252 case V_MFMA_F32_32X32X16_F16_mac_vgprcd_e64:
253 case V_MFMA_F32_32X32X16_F16_vgprcd_e64:
254 case V_MFMA_F32_32X32X16_F16_gfx940_acd:
255 case V_MFMA_F32_32X32X16_F16_gfx940_vcd:
256 case V_MFMA_SCALE_F32_32X32X64_F8F6F4_f4_f4_gfx940_acd:
257 case V_MFMA_SCALE_F32_32X32X64_F8F6F4_f4_f4_gfx940_vcd:
258 case V_MFMA_SCALE_F32_32X32X64_F8F6F4_f4_f6_gfx940_acd:
259 case V_MFMA_SCALE_F32_32X32X64_F8F6F4_f4_f6_gfx940_vcd:
260 case V_MFMA_SCALE_F32_32X32X64_F8F6F4_f6_f4_gfx940_acd:
261 case V_MFMA_SCALE_F32_32X32X64_F8F6F4_f6_f4_gfx940_vcd:
262 case V_MFMA_SCALE_F32_32X32X64_F8F6F4_f6_f6_gfx940_acd:
263 case V_MFMA_SCALE_F32_32X32X64_F8F6F4_f6_f6_gfx940_vcd:
264 case V_MFMA_SCALE_F32_32X32X64_F8F6F4_f4_f4_e64:
265 case V_MFMA_SCALE_F32_32X32X64_F8F6F4_f4_f6_e64:
266 case V_MFMA_SCALE_F32_32X32X64_F8F6F4_f6_f4_e64:
267 case V_MFMA_SCALE_F32_32X32X64_F8F6F4_f6_f6_e64:
268 case V_MFMA_SCALE_F32_32X32X64_F8F6F4_f4_f4_vgprcd_e64:
269 case V_MFMA_SCALE_F32_32X32X64_F8F6F4_f4_f6_vgprcd_e64:
270 case V_MFMA_SCALE_F32_32X32X64_F8F6F4_f6_f4_vgprcd_e64:
271 case V_MFMA_SCALE_F32_32X32X64_F8F6F4_f6_f6_vgprcd_e64:
272 case V_MFMA_SCALE_F32_32X32X64_F8F6F4_f4_f4_mac_e64:
273 case V_MFMA_SCALE_F32_32X32X64_F8F6F4_f4_f6_mac_e64:
274 case V_MFMA_SCALE_F32_32X32X64_F8F6F4_f6_f4_mac_e64:
275 case V_MFMA_SCALE_F32_32X32X64_F8F6F4_f6_f6_mac_e64:
276 case V_MFMA_SCALE_F32_32X32X64_F8F6F4_f4_f4_mac_vgprcd_e64:
277 case V_MFMA_SCALE_F32_32X32X64_F8F6F4_f4_f6_mac_vgprcd_e64:
278 case V_MFMA_SCALE_F32_32X32X64_F8F6F4_f6_f4_mac_vgprcd_e64:
279 case V_MFMA_SCALE_F32_32X32X64_F8F6F4_f6_f6_mac_vgprcd_e64:
280 Res.TotalWindow = 8;
284 return Res;
285
286 // 16-cycle occupancy, 20-cycle window.
287 case V_MFMA_F32_32X32X64_F8F6F4_f4_f8_e64:
288 case V_MFMA_F32_32X32X64_F8F6F4_f4_f8_mac_e64:
289 case V_MFMA_F32_32X32X64_F8F6F4_f4_f8_mac_vgprcd_e64:
290 case V_MFMA_F32_32X32X64_F8F6F4_f4_f8_vgprcd_e64:
291 case V_MFMA_F32_32X32X64_F8F6F4_f4_f8_gfx940_acd:
292 case V_MFMA_F32_32X32X64_F8F6F4_f4_f8_gfx940_vcd:
293 case V_MFMA_F32_32X32X64_F8F6F4_f6_f8_e64:
294 case V_MFMA_F32_32X32X64_F8F6F4_f6_f8_mac_e64:
295 case V_MFMA_F32_32X32X64_F8F6F4_f6_f8_mac_vgprcd_e64:
296 case V_MFMA_F32_32X32X64_F8F6F4_f6_f8_vgprcd_e64:
297 case V_MFMA_F32_32X32X64_F8F6F4_f6_f8_gfx940_acd:
298 case V_MFMA_F32_32X32X64_F8F6F4_f6_f8_gfx940_vcd:
299 case V_MFMA_F32_32X32X64_F8F6F4_f8_f4_e64:
300 case V_MFMA_F32_32X32X64_F8F6F4_f8_f4_mac_e64:
301 case V_MFMA_F32_32X32X64_F8F6F4_f8_f4_mac_vgprcd_e64:
302 case V_MFMA_F32_32X32X64_F8F6F4_f8_f4_vgprcd_e64:
303 case V_MFMA_F32_32X32X64_F8F6F4_f8_f4_gfx940_acd:
304 case V_MFMA_F32_32X32X64_F8F6F4_f8_f4_gfx940_vcd:
305 case V_MFMA_F32_32X32X64_F8F6F4_f8_f6_e64:
306 case V_MFMA_F32_32X32X64_F8F6F4_f8_f6_mac_e64:
307 case V_MFMA_F32_32X32X64_F8F6F4_f8_f6_mac_vgprcd_e64:
308 case V_MFMA_F32_32X32X64_F8F6F4_f8_f6_vgprcd_e64:
309 case V_MFMA_F32_32X32X64_F8F6F4_f8_f6_gfx940_acd:
310 case V_MFMA_F32_32X32X64_F8F6F4_f8_f6_gfx940_vcd:
311 case V_MFMA_F32_32X32X64_F8F6F4_f8_f8_e64:
312 case V_MFMA_F32_32X32X64_F8F6F4_f8_f8_mac_e64:
313 case V_MFMA_F32_32X32X64_F8F6F4_f8_f8_mac_vgprcd_e64:
314 case V_MFMA_F32_32X32X64_F8F6F4_f8_f8_vgprcd_e64:
315 case V_MFMA_F32_32X32X64_F8F6F4_f8_f8_gfx940_acd:
316 case V_MFMA_F32_32X32X64_F8F6F4_f8_f8_gfx940_vcd:
317 case V_MFMA_SCALE_F32_32X32X64_F8F6F4_f4_f8_e64:
318 case V_MFMA_SCALE_F32_32X32X64_F8F6F4_f6_f8_e64:
319 case V_MFMA_SCALE_F32_32X32X64_F8F6F4_f8_f4_e64:
320 case V_MFMA_SCALE_F32_32X32X64_F8F6F4_f8_f6_e64:
321 case V_MFMA_SCALE_F32_32X32X64_F8F6F4_f8_f8_e64:
322 case V_MFMA_SCALE_F32_32X32X64_F8F6F4_f4_f8_vgprcd_e64:
323 case V_MFMA_SCALE_F32_32X32X64_F8F6F4_f6_f8_vgprcd_e64:
324 case V_MFMA_SCALE_F32_32X32X64_F8F6F4_f8_f4_vgprcd_e64:
325 case V_MFMA_SCALE_F32_32X32X64_F8F6F4_f8_f6_vgprcd_e64:
326 case V_MFMA_SCALE_F32_32X32X64_F8F6F4_f8_f8_vgprcd_e64:
327 case V_MFMA_SCALE_F32_32X32X64_F8F6F4_f4_f8_mac_e64:
328 case V_MFMA_SCALE_F32_32X32X64_F8F6F4_f6_f8_mac_e64:
329 case V_MFMA_SCALE_F32_32X32X64_F8F6F4_f8_f4_mac_e64:
330 case V_MFMA_SCALE_F32_32X32X64_F8F6F4_f8_f6_mac_e64:
331 case V_MFMA_SCALE_F32_32X32X64_F8F6F4_f8_f8_mac_e64:
332 case V_MFMA_SCALE_F32_32X32X64_F8F6F4_f4_f8_mac_vgprcd_e64:
333 case V_MFMA_SCALE_F32_32X32X64_F8F6F4_f6_f8_mac_vgprcd_e64:
334 case V_MFMA_SCALE_F32_32X32X64_F8F6F4_f8_f4_mac_vgprcd_e64:
335 case V_MFMA_SCALE_F32_32X32X64_F8F6F4_f8_f6_mac_vgprcd_e64:
336 case V_MFMA_SCALE_F32_32X32X64_F8F6F4_f8_f8_mac_vgprcd_e64:
337 case V_MFMA_SCALE_F32_32X32X64_F8F6F4_f4_f8_gfx940_acd:
338 case V_MFMA_SCALE_F32_32X32X64_F8F6F4_f4_f8_gfx940_vcd:
339 case V_MFMA_SCALE_F32_32X32X64_F8F6F4_f6_f8_gfx940_acd:
340 case V_MFMA_SCALE_F32_32X32X64_F8F6F4_f6_f8_gfx940_vcd:
341 case V_MFMA_SCALE_F32_32X32X64_F8F6F4_f8_f4_gfx940_acd:
342 case V_MFMA_SCALE_F32_32X32X64_F8F6F4_f8_f4_gfx940_vcd:
343 case V_MFMA_SCALE_F32_32X32X64_F8F6F4_f8_f6_gfx940_acd:
344 case V_MFMA_SCALE_F32_32X32X64_F8F6F4_f8_f6_gfx940_vcd:
345 case V_MFMA_SCALE_F32_32X32X64_F8F6F4_f8_f8_gfx940_acd:
346 case V_MFMA_SCALE_F32_32X32X64_F8F6F4_f8_f8_gfx940_vcd:
347 Res.TotalWindow = 20;
352 return Res;
353
354 // 9-cycle occupancy, 12-cycle window.
355 case V_SMFMAC_F32_32X32X32_BF16_e64:
356 case V_SMFMAC_F32_32X32X32_BF16_gfx940:
357 case V_SMFMAC_I32_32X32X64_I8_e64:
358 case V_SMFMAC_I32_32X32X64_I8_gfx940:
359 case V_SMFMAC_F32_32X32X64_BF8_BF8_e64:
360 case V_SMFMAC_F32_32X32X64_BF8_BF8_gfx940:
361 case V_SMFMAC_F32_32X32X64_BF8_FP8_e64:
362 case V_SMFMAC_F32_32X32X64_BF8_FP8_gfx940:
363 case V_SMFMAC_F32_32X32X64_FP8_BF8_e64:
364 case V_SMFMAC_F32_32X32X64_FP8_BF8_gfx940:
365 case V_SMFMAC_F32_32X32X64_FP8_FP8_e64:
366 case V_SMFMAC_F32_32X32X64_FP8_FP8_gfx940:
367 case V_SMFMAC_F32_32X32X32_F16_e64:
368 case V_SMFMAC_F32_32X32X32_F16_gfx940:
369 Res.TotalWindow = 12;
373 return Res;
374
375 // 18-cycle occupancy, 19-cycle window.
376 case V_MFMA_F64_16X16X4F64_e64:
377 case V_MFMA_F64_16X16X4F64_mac_e64:
378 case V_MFMA_F64_16X16X4F64_mac_vgprcd_e64:
379 case V_MFMA_F64_16X16X4F64_vgprcd_e64:
380 Res.TotalWindow = 19;
383 return Res;
384
385 default:
386 // Default fallback: permissive 8-cycle pattern
387 return CoExecInfo::build(0, 9, "AAAAAAAAA");
388 }
389}
390
392 const SIInstrInfo &SII) {
393 if (MI.isDebugInstr())
395
396 unsigned Opc = MI.getOpcode();
397
398 // Check for specific opcodes first.
399 if (Opc == AMDGPU::ATOMIC_FENCE || Opc == AMDGPU::S_WAIT_ASYNCCNT ||
400 Opc == AMDGPU::S_WAIT_TENSORCNT || Opc == AMDGPU::S_BARRIER_WAIT ||
401 Opc == AMDGPU::S_BARRIER_SIGNAL_IMM || SII.isWaitcnt(Opc))
403
404 if (SII.isLDSDMA(MI))
406
407 if (SII.isMFMA(MI)) {
408 // TODO: Consider further sub-classifying this (XDL, XDL2x, S/DGEMM).
409 // GFX9 SPG sub-classifies MFMA into XDL, XDL2x and S/DGEMM, because only
410 // certain sub-classes can be co-executed in certain slots. For now, we
411 // simply treat them all as one to simplify the change and leave the rest
412 // to a follow-up fine-tuning.
414 }
415
416 if (SII.isWMMA(MI) || SII.isSWMMAC(MI))
418
419 if (SII.isTRANS(MI))
421
422 if (SII.isVALU(MI, /*AllowLDSDMA=*/false)) {
423 if (SII.getBlockingCycles(MI) > 1)
425
427 }
428
429 if (SII.isSMRD(MI))
431
432 if (SII.isDS(MI))
434
435 if (SII.isVMEM(MI))
437
438 if (SII.isSALU(MI))
440
442}
443
445 for (SUnit *PrioritySU : PrioritySUs) {
446 if (!PrioritySU->isTopReady())
447 return PrioritySU;
448 }
449
450 if (!LookDeep)
451 return nullptr;
452
453 unsigned MinDepth = std::numeric_limits<unsigned int>::max();
454 SUnit *TargetSU = nullptr;
455 for (auto *SU : AllSUs) {
456 if (SU->isScheduled)
457 continue;
458
459 if (SU->isTopReady())
460 continue;
461
462 if (SU->getDepth() < MinDepth) {
463 MinDepth = SU->getDepth();
464 TargetSU = SU;
465 }
466 }
467 return TargetSU;
468}
469
470void HardwareUnitInfo::insert(SUnit *SU, unsigned BlockingCycles) {
471 if (!AllSUs.insert(SU))
472 llvm_unreachable("HardwareUnit already contains SU!");
473
474 TotalCycles += BlockingCycles;
475
476 if (PrioritySUs.empty()) {
477 PrioritySUs.insert(SU);
478 return;
479 }
480 unsigned SUDepth = SU->getDepth();
481 unsigned CurrDepth = (*PrioritySUs.begin())->getDepth();
482 if (SUDepth > CurrDepth)
483 return;
484
485 if (SUDepth == CurrDepth) {
486 PrioritySUs.insert(SU);
487 return;
488 }
489
490 // SU is lower depth and should be prioritized.
491 PrioritySUs.clear();
492 PrioritySUs.insert(SU);
493}
494
495void HardwareUnitInfo::markScheduled(SUnit *SU, unsigned BlockingCycles) {
496 // We may want to ignore some HWUIs (e.g. InstructionFlavor::Other). To do so,
497 // we just clear the HWUI. However, we still have instructions which map to
498 // this HWUI. Don't bother managing the state for these HWUI.
499 if (TotalCycles == 0)
500 return;
501
502 ScheduledSUs.push_back(SU);
503 AllSUs.remove(SU);
504 PrioritySUs.remove(SU);
505
506 // BufferSize 0 is unlimited, while size 1 has no parallel buffering. In
507 // either case, each SU uses the HardwareUnit for BlockingCycles.
508 if (BufferSize <= 1 || (ScheduledSUs.size() % BufferSize == 0))
509 TotalCycles -= std::min(TotalCycles, BlockingCycles);
510
511 if (AllSUs.empty())
512 return;
513 if (PrioritySUs.empty()) {
514 for (auto SU : AllSUs) {
515 if (PrioritySUs.empty()) {
516 PrioritySUs.insert(SU);
517 continue;
518 }
519 unsigned SUDepth = SU->getDepth();
520 unsigned CurrDepth = (*PrioritySUs.begin())->getDepth();
521 if (SUDepth > CurrDepth)
522 continue;
523
524 if (SUDepth == CurrDepth) {
525 PrioritySUs.insert(SU);
526 continue;
527 }
528
529 // SU is lower depth and should be prioritized.
530 PrioritySUs.clear();
531 PrioritySUs.insert(SU);
532 }
533 }
534}
535
537 if (BufferSize == 0 || AllSUs.empty())
538 return;
539
540 // We estimate the amount of cycles it takes to free up a slot in the buffer
541 // as the average cycles per SU.
542 BufferCycles = TotalCycles / AllSUs.size();
543 // A single-entry buffer does not reduce TotalCycles.
544 if (BufferSize == 1)
545 return;
546
547 // The TotalCycles is normalized against the BufferSize.
548 // This provides an estimate of the TotalCycles which is not always accurate
549 // -- particularly in cases where we have fewer instructions than the
550 // BufferSize. For example, if we have 2 instructions which each take 50
551 // cycles and a BufferSize of 16, then a TotalCycles of 51 cycles would be
552 // somewhat accurate. This normalization calculates TotalCycles as 6. However,
553 // if we have 64 of these instructions, our normalized estimate of 200 is more
554 // reasonable, given the more accurate measure is 264. Having a completely
555 // accurate measure is not very important, since this metric is mainly used to
556 // compare the relative demand per HardwareUnit across the region. The simpler
557 // estimate makes managing the metric incrementally during scheduling much
558 // simpler.
559 TotalCycles /= BufferSize;
560}
561
564 for (HardwareUnitInfo &HWUICand : HWUInfo) {
565 if (HWUICand.getType() == Flavor) {
566 return &HWUICand;
567 }
568 }
569 return nullptr;
570}
571
573 const MachineInstr *MI) {
574 // Loads and stores are not pipelined.
575 if (MI->mayLoadOrStore())
576 return SchedModel->computeInstrLatency(MI, false);
577
578 unsigned ReleaseAtCycle = 0;
579 for (TargetSchedModel::ProcResIter PI = SchedModel->getWriteProcResBegin(SC),
580 PE = SchedModel->getWriteProcResEnd(SC);
581 PI != PE; ++PI) {
582 ReleaseAtCycle =
583 std::max(ReleaseAtCycle, static_cast<unsigned>(PI->ReleaseAtCycle));
584 }
585 ReleaseAtCycle = std::max(ReleaseAtCycle, SII->getBlockingCycles(*MI));
586 return ReleaseAtCycle;
587}
588
590 assert(SchedModel && SchedModel->hasInstrSchedModel());
591 MachineInstr *MI = SU->getInstr();
592 if (SII->isDS(*MI))
593 return SchedModel->computeInstrLatency(MI);
594 return getMaxBlockingCycles(DAG->getSchedClass(SU), MI);
595}
596
598 assert(SchedModel && SchedModel->hasInstrSchedModel());
599 return getMaxBlockingCycles(SchedModel->resolveSchedClass(MI), MI);
600}
601
608
611 const TargetRegisterInfo *TRI) {
612 DAG = SchedDAG;
614 assert(SchedModel && SchedModel->hasInstrSchedModel());
615
616 SRI = static_cast<const SIRegisterInfo *>(TRI);
617 SII = static_cast<const SIInstrInfo *>(DAG->TII);
618
619 HWUInfo.resize(static_cast<int>(InstructionFlavor::NUM_FLAVORS));
620
621 for (unsigned I = 0; I < HWUInfo.size(); I++) {
622 HWUInfo[I].reset();
623 HWUInfo[I].setType(I);
624 }
625
626 HWUInfo[static_cast<int>(InstructionFlavor::WMMA)].setProducesCoexecWindow(
627 true);
629 .setProducesCoexecWindow(true);
630 HWUInfo[static_cast<int>(InstructionFlavor::TRANS)].setProducesCoexecWindow(
631 true);
632 HWUInfo[static_cast<int>(InstructionFlavor::DS)].setBufferSize(
634
636}
637
639 if (BlockCarriedLatency == CarriedLatency::Off)
640 return 0;
641
642 MachineInstr *MI = SU->getInstr();
643 unsigned CarriedLatency = 0;
644 const InstructionFlavor Flavor = classifyFlavor(*MI, *SII);
645 if (Flavor == InstructionFlavor::Fence) {
646 MachineBasicBlock *MBB = MI->getParent();
647 // Scan each direct predecessor back to its nearest Fence or block start for
648 // DS instructions.
649 for (auto PredMBB : MBB->predecessors()) {
650 auto I = PredMBB->rbegin();
651 auto E = PredMBB->rend();
652 for (; I != E; I++) {
653 const InstructionFlavor ItFlavor = classifyFlavor(*I, *SII);
654 if (ItFlavor == InstructionFlavor::Fence)
655 break;
656
657 // Found carried latency.
658 if (ItFlavor == InstructionFlavor::DS)
659 CarriedLatency = std::max(CarriedLatency, getHWUICyclesForMI(&*I));
660 }
661 }
662 }
663
664 if (BlockCarriedLatency == CarriedLatency::Fence)
665 return CarriedLatency;
666
667 for (MachineOperand &Op : MI->all_uses()) {
668 auto Reg = Op.getReg();
669 if (!Reg.isVirtual())
670 continue;
671
672 for (MachineInstr &Def : DAG->MRI.def_instructions(Reg)) {
673 // We don't have the proper modelling to accurately measure all carried
674 // latency. Just try to measure carried latency for long latency loads to
675 // avoid long stalls.
676 if (!Def.mayLoad())
677 continue;
678
679 unsigned Latency = getHWUICyclesForMI(&Def);
680
681 // Load is carried across block.
682 if (Def.getParent() != MI->getParent()) {
683 bool FoundUseInDefBlock = false;
684 for (MachineInstr &Use : DAG->MRI.use_nodbg_instructions(Reg)) {
685 if (Use.getParent() != Def.getParent())
686 continue;
687
688 SlotIndex DefIdx = DAG->getLIS()->getInstructionIndex(Def);
689 SlotIndex UseIdx = DAG->getLIS()->getInstructionIndex(Use);
690 // We have a use of this load in the def block that occurs after the
691 // load. In this case we must wait for the load in the def block, and
692 // we do not have any carried latency from this load.
693 if (SlotIndex::isEarlierInstr(DefIdx, UseIdx)) {
694 FoundUseInDefBlock = true;
695 break;
696 }
697 }
698 if (!FoundUseInDefBlock)
699 CarriedLatency = std::max(Latency, CarriedLatency);
700
701 continue;
702 }
703
704 assert(Def.getParent() == MI->getParent());
705 // Load is in the same block.
706 SlotIndex LoadIdx = DAG->getLIS()->getInstructionIndex(Def);
707 SlotIndex UseIdx = DAG->getLIS()->getInstructionIndex(*MI);
708 // The load occurs after this use -- the latency is carried across loop
709 // backedge.
710 if (SlotIndex::isEarlierInstr(UseIdx, LoadIdx))
711 CarriedLatency = std::max(Latency, CarriedLatency);
712 }
713 }
714 return CarriedLatency;
715}
716
718 CarriedLatencies.clear();
719 if (!SchedModel || !SchedModel->hasInstrSchedModel())
720 return;
721
722 for (auto &SU : DAG->SUnits) {
723 MachineInstr *MI = SU.getInstr();
724 const InstructionFlavor Flavor = classifyFlavor(*MI, *SII);
725 HWUInfo[static_cast<int>(Flavor)].insert(&SU, getHWUICyclesForSU(&SU));
726 unsigned CarriedLatency = getCarriedLatency(&SU);
727 if (CarriedLatency)
728 CarriedLatencies[MI] = CarriedLatency;
729 }
730
731 for (auto &HWUI : HWUInfo)
732 HWUI.finalizeCycles();
733
735}
736
738 MachineBasicBlock *BB = DAG->begin()->getParent();
739 dbgs() << "\n=== Region: " << DAG->MF.getName() << " BB" << BB->getNumber()
740 << " (" << DAG->SUnits.size() << " SUs) ===\n";
741
742 dbgs() << "\nHWUI Resource Pressure:\n";
743 for (auto &HWUI : HWUInfo) {
744 if (HWUI.getTotalCycles() == 0)
745 continue;
746
747 StringRef Name = getFlavorName(HWUI.getType());
748 dbgs() << " " << Name << ": " << HWUI.getTotalCycles() << " cycles, "
749 << HWUI.size() << " instrs\n";
750 }
751 dbgs() << "\n";
752}
753
755 // Highest priority should be first.
757 // Prefer CoexecWindow producers
758 if (A.producesCoexecWindow() != B.producesCoexecWindow())
759 return A.producesCoexecWindow();
760
761 // Prefer more demanded resources
762 if (A.getTotalCycles() != B.getTotalCycles())
763 return A.getTotalCycles() > B.getTotalCycles();
764
765 // In ties -- prefer the resource with more instructions
766 if (A.size() != B.size())
767 return A.size() < B.size();
768
769 // Default to Flavor order
770 return static_cast<unsigned>(A.getType()) <
771 static_cast<unsigned>(B.getType());
772 });
773}
774
776 SUnit *SU) {
777 assert(Zone.isTop() && "effective stall comparison requires top boundary");
778 if (!SU)
779 return 0;
780
781 MachineInstr *MI = SU->getInstr();
782 unsigned CurrCycle = Zone.getCurrCycle();
783 unsigned Stall = 0;
784
785 // Query SchedModel for resource stalls (unbuffered resources).
786 if (SchedModel->hasInstrSchedModel() && SU->hasReservedResource) {
787 const MCSchedClassDesc *SC = DAG->getSchedClass(SU);
788 for (const MCWriteProcResEntry &PE :
789 make_range(SchedModel->getWriteProcResBegin(SC),
790 SchedModel->getWriteProcResEnd(SC))) {
791 unsigned NextAvail =
792 Zone.getNextResourceCycle(SC, PE.ProcResourceIdx, PE.ReleaseAtCycle,
793 PE.AcquireAtCycle)
794 .first;
795 if (NextAvail > CurrCycle)
796 Stall = std::max(Stall, NextAvail - CurrCycle);
797 }
798 }
799
800 // Query HazardRecognizer for sequence-dependent hazard penalties.
801 if (Zone.HazardRec && Zone.HazardRec->isEnabled()) {
802 auto *HR = static_cast<GCNHazardRecognizer *>(Zone.HazardRec.get());
803 Stall = std::max(Stall, HR->getHazardWaitStates(MI));
804 }
805
806 return Stall;
807}
808
811 if (!Zone.isTop())
812 return {};
813
814 auto getBufferFullStalls = [this, &Zone](SUnit *SU) -> unsigned {
816 *SU->getInstr(), *static_cast<const SIInstrInfo *>(DAG->TII));
817 HardwareUnitInfo *HWUI = getHWUIFromFlavor(Flavor);
818
819 // A BufferSize of 0 means "unlimited" buffer, thus we will never fill it.
820 if (HWUI->getBufferSize() == 0)
821 return 0;
822
823 unsigned CurrCycle = Zone.getCurrCycle();
824 unsigned BufferReadyCycle = HWUI->getBufferAvailableCycle(CurrCycle);
825 if (BufferReadyCycle <= CurrCycle)
826 return 0;
827
828 return BufferReadyCycle - CurrCycle;
829 };
830
831 unsigned CurrCycle = Zone.getCurrCycle();
832
833 auto getFenceStalls = [this, &CurrCycle](SUnit *SU) -> unsigned {
835 *SU->getInstr(), *static_cast<const SIInstrInfo *>(DAG->TII));
836
837 if (Flavor != InstructionFlavor::Fence)
838 return 0;
839
840 HardwareUnitInfo *ConsumerHWUI = getHWUIFromFlavor(Flavor);
842
843 SUnit *LastProducer = ProducerHWUI->getLastScheduledSU();
844 if (!LastProducer)
845 return 0;
846
847 SUnit *LastConsumer = ConsumerHWUI->getLastScheduledSU();
848 unsigned LastConsumerCycle = LastConsumer ? LastConsumer->TopReadyCycle : 0;
849 unsigned LastProducerCycle = LastProducer->TopReadyCycle;
850
851 if (LastProducerCycle < LastConsumerCycle)
852 return 0;
853
854 unsigned FenceStallFinish =
855 LastProducerCycle + getHWUICyclesForSU(LastProducer);
856 return FenceStallFinish <= CurrCycle ? 0 : FenceStallFinish - CurrCycle;
857 };
858
859 unsigned ReadyCycle = SU->TopReadyCycle;
860 StallCosts Costs;
861 Costs.Ready = ReadyCycle > CurrCycle ? ReadyCycle - CurrCycle : 0;
862 Costs.Structural = getStructuralStallCycles(Zone, SU);
863 Costs.Latency = Zone.getLatencyStallCycles(SU);
864 unsigned CarriedLatency = CarriedLatencies.lookup_or(SU->getInstr(), 0);
865 Costs.Carried = CarriedLatency > CurrCycle ? CarriedLatency - CurrCycle : 0;
866 Costs.Buffer = getBufferFullStalls(SU);
867 Costs.Fence = getFenceStalls(SU);
868 Costs.Effective = std::max({Costs.Ready, Costs.Structural, Costs.Latency,
869 Costs.Carried, Costs.Buffer, Costs.Fence});
870 return Costs;
871}
872
876 // Only implemented for top-down scheduling
877 if (!Zone.isTop())
878 return 0;
879
880 StallCosts TryCosts = getStallCosts(TryCand.SU, Zone);
881 StallCosts CandCosts = getStallCosts(Cand.SU, Zone);
882
883 LLVM_DEBUG(if (TryCosts.Effective || CandCosts.Effective) {
884 dbgs() << "Effective stalls: try=" << TryCosts.Effective
885 << " (ready=" << TryCosts.Ready << ", struct=" << TryCosts.Structural
886 << ", lat=" << TryCosts.Latency << ", carried=" << TryCosts.Carried
887 << ", buffer=" << TryCosts.Buffer << ", fence=" << TryCosts.Fence
888 << ") cand=" << CandCosts.Effective << " (ready=" << CandCosts.Ready
889 << ", struct=" << CandCosts.Structural
890 << ", lat=" << CandCosts.Latency << ", carried=" << CandCosts.Carried
891 << ", buffer=" << CandCosts.Buffer << ", fence=" << CandCosts.Fence
892 << ")\n";
893 });
894
895 return tryLess(TryCosts.Effective, CandCosts.Effective, TryCand, Cand,
897}
898
902
903 InstructionFlavor TryFlavor = classifyFlavor(*TryCand.SU->getInstr(), *SII);
904
905 InstructionFlavor CandFlavor = classifyFlavor(*Cand.SU->getInstr(), *SII);
906
907 bool TryIsMemoryPipeline = TryFlavor == InstructionFlavor::DMA ||
908 TryFlavor == InstructionFlavor::Fence;
909 bool CandIsMemoryPipeline = CandFlavor == InstructionFlavor::DMA ||
910 CandFlavor == InstructionFlavor::Fence;
911
912 if (!(TryIsMemoryPipeline || CandIsMemoryPipeline))
913 return false;
914
915 if (TryIsMemoryPipeline)
916 TryIsMemoryPipeline &= getStallCosts(TryCand.SU, Zone).Effective == 0;
917
918 if (CandIsMemoryPipeline)
919 CandIsMemoryPipeline &= getStallCosts(Cand.SU, Zone).Effective == 0;
920
921 if (TryIsMemoryPipeline == CandIsMemoryPipeline)
922 return false;
923
924 if (CandIsMemoryPipeline) {
927
928 return true;
929 }
930
932 return true;
933}
934
938
939 auto HasPrioritySU = [this, &Cand, &TryCand](unsigned ResourceIdx) {
940 const HardwareUnitInfo &HWUI = HWUInfo[ResourceIdx];
941
942 auto CandFlavor = classifyFlavor(*Cand.SU->getInstr(), *SII);
943 auto TryCandFlavor = classifyFlavor(*TryCand.SU->getInstr(), *SII);
944 bool LookDeep = (CandFlavor == InstructionFlavor::DS ||
945 TryCandFlavor == InstructionFlavor::DS) &&
947 auto *TargetSU = HWUI.getNextTargetSU(LookDeep);
948
949 // If we do not have a TargetSU for this resource, then it is not critical.
950 if (!TargetSU)
951 return false;
952
953 return true;
954 };
955
956 auto TryEnablesResource = [&Cand, &TryCand, this](unsigned ResourceIdx) {
957 const HardwareUnitInfo &HWUI = HWUInfo[ResourceIdx];
958 auto CandFlavor = classifyFlavor(*Cand.SU->getInstr(), *SII);
959
960 // We want to ensure our DS order matches WMMA order.
961 bool LookDeep = CandFlavor == InstructionFlavor::DS &&
963 auto *TargetSU = HWUI.getNextTargetSU(LookDeep);
964
965 bool CandEnables =
966 TargetSU != Cand.SU && DAG->IsReachable(TargetSU, Cand.SU);
967 bool TryCandEnables =
968 TargetSU != TryCand.SU && DAG->IsReachable(TargetSU, TryCand.SU);
969
970 if (!CandEnables && !TryCandEnables)
971 return false;
972
973 if (CandEnables && !TryCandEnables) {
976
977 return true;
978 }
979
980 if (!CandEnables && TryCandEnables) {
982 return true;
983 }
984
985 // Both enable, prefer the critical path.
986 unsigned CandHeight = Cand.SU->getHeight();
987 unsigned TryCandHeight = TryCand.SU->getHeight();
988
989 if (CandHeight > TryCandHeight) {
992
993 return true;
994 }
995
996 if (CandHeight < TryCandHeight) {
998 return true;
999 }
1000
1001 // Same critical path, just prefer original candidate.
1004
1005 return true;
1006 };
1007
1008 for (unsigned I = 0; I < HWUInfo.size(); I++) {
1009 // If we have encountered a resource that is not critical, then neither
1010 // candidate enables a critical resource
1011 if (!HasPrioritySU(I))
1012 continue;
1013
1014 bool Enabled = TryEnablesResource(I);
1015 // If neither has enabled the resource, continue to the next resource
1016 if (Enabled)
1017 return true;
1018 }
1019 return false;
1020}
1021
1025 for (unsigned I = 0; I < HWUInfo.size(); I++) {
1026 const HardwareUnitInfo &HWUI = HWUInfo[I];
1027
1028 bool CandUsesCrit = HWUI.contains(Cand.SU);
1029 bool TryCandUsesCrit = HWUI.contains(TryCand.SU);
1030
1031 if (!CandUsesCrit && !TryCandUsesCrit)
1032 continue;
1033
1034 if (CandUsesCrit != TryCandUsesCrit) {
1035 if (CandUsesCrit) {
1038 return true;
1039 }
1041 return true;
1042 }
1043
1044 // Otherwise, both use the critical resource
1045 // For longer latency InstructionFlavors, we should prioritize first by
1046 // their enablement of critical resources
1047 if (HWUI.getType() == InstructionFlavor::DS) {
1048 if (tryCriticalResourceDependency(TryCand, Cand, Zone))
1049 return true;
1050 }
1051
1052 // Prioritize based on HWUI priorities.
1053 SUnit *Match = HWUI.getHigherPriority(Cand.SU, TryCand.SU);
1054 if (Match) {
1055 if (Match == Cand.SU) {
1058 return true;
1059 }
1061 return true;
1062 }
1063 }
1064
1065 return false;
1066}
1067
1081
1084 unsigned NumRegionInstrs) {
1088 report_fatal_error("CoExecSchedStrategy only support TopDown scheduling.");
1089 RegionPolicy.OnlyTopDown = true;
1090 RegionPolicy.OnlyBottomUp = false;
1091 RegionPolicy.ShouldTrackLaneMasks = true;
1092}
1093
1095 // Coexecution scheduling strategy is only done top-down to support new
1096 // resource balancing heuristics.
1097 RegionPolicy.OnlyTopDown = true;
1098 RegionPolicy.OnlyBottomUp = false;
1099
1101 Heurs.initialize(DAG, SchedModel, TRI);
1102
1103 // Replace the default hazard recognizer with our PreRA one so that pre-RA
1104 // scheduling accounts for WMMA co-execution slot constraints. This must
1105 // happen after GCNSchedStrategy::initialize() because
1106 // GenericScheduler::initialize() calls SchedBoundary::reset(), which deletes
1107 // and recreates the hazard recognizer each region.
1108 Top.HazardRec = std::make_unique<GCNHazardRecognizer>(
1110}
1111
1113 Heurs.updateForScheduling(SU);
1114 GCNSchedStrategy::schedNode(SU, IsTopNode);
1115}
1116
1118 assert(RegionPolicy.OnlyTopDown && !RegionPolicy.OnlyBottomUp &&
1119 "coexec scheduler only supports top-down scheduling");
1120
1121 if (DAG->top() == DAG->bottom()) {
1122 assert(Top.Available.empty() && Top.Pending.empty() &&
1123 Bot.Available.empty() && Bot.Pending.empty() && "ReadyQ garbage");
1124 return nullptr;
1125 }
1126
1127 bool PickedPending = false;
1128 SUnit *SU = nullptr;
1129#ifndef NDEBUG
1130 SchedCandidate *PickedCand = nullptr;
1131#endif
1132 do {
1133 PickedPending = false;
1134 SU = pickOnlyChoice(Top);
1135 if (!SU) {
1136 CandPolicy NoPolicy;
1137 TopCand.reset(NoPolicy);
1138 pickNodeFromQueue(Top, NoPolicy, DAG->getTopRPTracker(), TopCand,
1139 PickedPending, /*IsBottomUp=*/false);
1140 assert(TopCand.Reason != NoCand && "failed to find a candidate");
1141 SU = TopCand.SU;
1142#ifndef NDEBUG
1143 PickedCand = &TopCand;
1144#endif
1145 }
1146 IsTopNode = true;
1147 } while (SU->isScheduled);
1148
1149 LLVM_DEBUG(if (PickedCand) dumpPickSummary(SU, IsTopNode, *PickedCand));
1150
1151 if (PickedPending) {
1152 unsigned ReadyCycle = SU->TopReadyCycle;
1153 unsigned CurrentCycle = Top.getCurrCycle();
1154 if (ReadyCycle > CurrentCycle)
1155 Top.bumpCycle(ReadyCycle);
1156
1157 // checkHazard() does not expose the exact cycle where the hazard clears.
1158 while (Top.checkHazard(SU))
1159 Top.bumpCycle(Top.getCurrCycle() + 1);
1160
1161 Top.releasePending();
1162 }
1163
1164 if (SU->isTopReady())
1165 Top.removeReady(SU);
1166 if (SU->isBottomReady())
1167 Bot.removeReady(SU);
1168
1169 LLVM_DEBUG(dbgs() << "Scheduling SU(" << SU->NodeNum << ") "
1170 << *SU->getInstr());
1171
1172 assert(IsTopNode && "coexec scheduler must only schedule from top boundary");
1173 return SU;
1174}
1175
1177 SchedBoundary &Zone, const CandPolicy &ZonePolicy,
1178 const RegPressureTracker &RPTracker, SchedCandidate &Cand,
1179 bool &PickedPending, bool IsBottomUp) {
1180 assert(Zone.isTop() && "coexec scheduler only supports top boundary");
1181 assert(!IsBottomUp && "coexec scheduler only supports top-down scheduling");
1182
1183 const SIRegisterInfo *SRI = static_cast<const SIRegisterInfo *>(TRI);
1185 unsigned SGPRPressure = 0;
1186 unsigned VGPRPressure = 0;
1187 unsigned AGPRPressure = 0;
1188 PickedPending = false;
1189 if (DAG->isTrackingPressure()) {
1190 if (!useGCNTrackers()) {
1191 SGPRPressure = Pressure[AMDGPU::RegisterPressureSets::SReg_32];
1192 VGPRPressure = Pressure[AMDGPU::RegisterPressureSets::VGPR_32];
1193 AGPRPressure = Pressure[AMDGPU::RegisterPressureSets::AGPR_32];
1194 } else {
1195 SGPRPressure = DownwardTracker.getPressure().getSGPRNum();
1196 VGPRPressure = DownwardTracker.getPressure().getArchVGPRNum();
1197 AGPRPressure = DownwardTracker.getPressure().getAGPRNum();
1198 }
1199 }
1200
1201 auto EvaluateQueue = [&](ReadyQueue &Q, bool FromPending) {
1202 for (SUnit *SU : Q) {
1203 SchedCandidate TryCand(ZonePolicy);
1204 initCandidate(TryCand, SU, Zone.isTop(), RPTracker, SRI, SGPRPressure,
1205 VGPRPressure, AGPRPressure, IsBottomUp);
1206 SchedBoundary *ZoneArg = Cand.AtTop == TryCand.AtTop ? &Zone : nullptr;
1207 tryCandidateCoexec(Cand, TryCand, ZoneArg);
1208 if (TryCand.Reason != NoCand) {
1209 if (TryCand.ResDelta == SchedResourceDelta())
1210 TryCand.initResourceDelta(Zone.DAG, SchedModel);
1211 LLVM_DEBUG(printCandidateDecision(Cand, TryCand));
1212 PickedPending = FromPending;
1213 Cand.setBest(TryCand);
1214 } else {
1215 LLVM_DEBUG(printCandidateDecision(TryCand, Cand));
1216 }
1217 }
1218 };
1219
1220 LLVM_DEBUG(dbgs() << "Available Q:\n");
1221 EvaluateQueue(Zone.Available, /*FromPending=*/false);
1222
1223 LLVM_DEBUG(dbgs() << "Pending Q:\n");
1224 EvaluateQueue(Zone.Pending, /*FromPending=*/true);
1225}
1226
1227#ifndef NDEBUG
1229 SchedCandidate &Cand) {
1230 const SIInstrInfo *SII = static_cast<const SIInstrInfo *>(DAG->TII);
1231 unsigned Cycle = IsTopNode ? Top.getCurrCycle() : Bot.getCurrCycle();
1232
1233 dbgs() << "=== Pick @ Cycle " << Cycle << " ===\n";
1234
1235 const InstructionFlavor Flavor = classifyFlavor(*SU->getInstr(), *SII);
1236 dbgs() << "Picked: SU(" << SU->NodeNum << ") ";
1237 SU->getInstr()->print(dbgs(), /*IsStandalone=*/true, /*SkipOpers=*/false,
1238 /*SkipDebugLoc=*/true);
1239 dbgs() << " [" << getFlavorName(Flavor) << "]\n";
1240
1241 dbgs() << " Reason: ";
1244 else if (Cand.Reason != NoCand)
1246 else
1247 dbgs() << "Unknown";
1248 dbgs() << "\n\n";
1249
1251}
1252#endif
1253
1255 SchedCandidate &TryCand,
1256 SchedBoundary *Zone) {
1257 // Initialize the candidate if needed.
1258 if (!Cand.isValid()) {
1259 TryCand.Reason = FirstValid;
1260 return true;
1261 }
1262
1263 // Bias PhysReg Defs and copies to their uses and defined respectively.
1264 if (tryGreater(biasPhysReg(TryCand.SU, TryCand.AtTop),
1265 biasPhysReg(Cand.SU, Cand.AtTop), TryCand, Cand, PhysReg))
1266 return TryCand.Reason != NoCand;
1267
1268 // Avoid exceeding the target's limit.
1269 if (DAG->isTrackingPressure() &&
1270 tryPressure(TryCand.RPDelta.Excess, Cand.RPDelta.Excess, TryCand, Cand,
1271 RegExcess, TRI, DAG->MF))
1272 return TryCand.Reason != NoCand;
1273
1274 // We only compare a subset of features when comparing nodes between
1275 // Top and Bottom boundary. Some properties are simply incomparable, in many
1276 // other instances we should only override the other boundary if something
1277 // is a clear good pick on one boundary. Skip heuristics that are more
1278 // "tie-breaking" in nature.
1279 bool SameBoundary = Zone != nullptr;
1280 if (SameBoundary) {
1281 // Compare candidates by the stall they would introduce if
1282 // scheduled in the current cycle.
1283 if (Heurs.tryEffectiveStall(TryCand, Cand, *Zone)) {
1285 return TryCand.Reason != NoCand;
1286 }
1287
1288 if (Heurs.tryMemoryPipeline(TryCand, Cand, *Zone)) {
1290 return TryCand.Reason != NoCand;
1291 }
1292
1293 Heurs.sortHWUIResources();
1294 if (Heurs.tryCriticalResource(TryCand, Cand, Zone)) {
1296 return TryCand.Reason != NoCand;
1297 }
1298
1299 if (Heurs.tryCriticalResourceDependency(TryCand, Cand, Zone)) {
1301 return TryCand.Reason != NoCand;
1302 }
1303 }
1304
1305 // Keep clustered nodes together to encourage downstream peephole
1306 // optimizations which may reduce resource requirements.
1307 //
1308 // This is a best effort to set things up for a post-RA pass. Optimizations
1309 // like generating loads of multiple registers should ideally be done within
1310 // the scheduler pass by combining the loads during DAG postprocessing.
1311 unsigned CandZoneCluster = Cand.AtTop ? TopClusterID : BotClusterID;
1312 unsigned TryCandZoneCluster = TryCand.AtTop ? TopClusterID : BotClusterID;
1313 bool CandIsClusterSucc =
1314 isTheSameCluster(CandZoneCluster, Cand.SU->ParentClusterIdx);
1315 bool TryCandIsClusterSucc =
1316 isTheSameCluster(TryCandZoneCluster, TryCand.SU->ParentClusterIdx);
1317
1318 if (tryGreater(TryCandIsClusterSucc, CandIsClusterSucc, TryCand, Cand,
1319 Cluster))
1320 return TryCand.Reason != NoCand;
1321
1322 if (SameBoundary) {
1323 // Weak edges are for clustering and other constraints.
1324 if (tryLess(getWeakLeft(TryCand.SU, TryCand.AtTop),
1325 getWeakLeft(Cand.SU, Cand.AtTop), TryCand, Cand, Weak))
1326 return TryCand.Reason != NoCand;
1327 }
1328
1329 // Avoid increasing the max pressure of the entire region.
1330 if (DAG->isTrackingPressure() &&
1331 tryPressure(TryCand.RPDelta.CurrentMax, Cand.RPDelta.CurrentMax, TryCand,
1332 Cand, RegMax, TRI, DAG->MF))
1333 return TryCand.Reason != NoCand;
1334
1335 if (SameBoundary) {
1336 // Avoid serializing long latency dependence chains.
1337 // For acyclic path limited loops, latency was already checked above.
1338 if (!RegionPolicy.DisableLatencyHeuristic && TryCand.Policy.ReduceLatency &&
1339 !Rem.IsAcyclicLatencyLimited && tryLatency(TryCand, Cand, *Zone))
1340 return TryCand.Reason != NoCand;
1341
1342 // Fall through to original instruction order.
1343 if ((Zone->isTop() && TryCand.SU->NodeNum < Cand.SU->NodeNum) ||
1344 (!Zone->isTop() && TryCand.SU->NodeNum > Cand.SU->NodeNum)) {
1345 TryCand.Reason = NodeOrder;
1346 return true;
1347 }
1348 }
1349
1350 return false;
1351}
1352
1355 LLVM_DEBUG(dbgs() << "AMDGPU coexec preRA scheduler selected for "
1356 << C->MF->getName() << '\n');
1358 C, std::make_unique<AMDGPUCoExecSchedStrategy>(C));
1361 return DAG;
1362}
1363
1366 LLVM_DEBUG(dbgs() << "AMDGPU nop postRA scheduler selected for "
1367 << C->MF->getName() << '\n');
1368 return new GCNNoopPostScheduleDAG(C);
1369}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static cl::opt< CarriedLatency > BlockCarriedLatency("amdgpu-block-carried-latency", cl::Hidden, cl::init(CarriedLatency::Off), cl::desc("Estimate block-carried latency and include it in the effective " "candidate stall cost."), cl::values(clEnumValN(CarriedLatency::Off, "off", "Disabled - do not pad latency."), clEnumValN(CarriedLatency::Fence, "fence", "Only pad latency for memory fence (e.g. those surrounding " "barrier_signal/wait)."), clEnumValN(CarriedLatency::All, "all", "Pad latency for any SU with an incoming ds_load dependency.")))
static SUnit * pickOnlyChoice(SchedBoundary &Zone)
static constexpr unsigned DefaultCoExecVGPRThresholdPercent
static void allowCoExec(llvm::AMDGPU::CoExecInfo &Info, llvm::AMDGPU::CoExecMaskT ExtraBits, unsigned StartIndex)
Apply ExtraBits to every slot in Info starting with StartIndex Used by MFMA co-exec rules,...
Coexecution-focused scheduling strategy for AMDGPU.
MachineBasicBlock & MBB
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
#define clEnumValN(ENUMVAL, FLAGNAME, DESC)
IRTranslator LLVM IR MI
#define I(x, y, z)
Definition MD5.cpp:57
Register const TargetRegisterInfo * TRI
#define LLVM_DEBUG(...)
Definition Debug.h:119
void initPolicy(MachineBasicBlock::iterator Begin, MachineBasicBlock::iterator End, unsigned NumRegionInstrs) override
Optionally override the per-region scheduling policy.
SUnit * pickNode(bool &IsTopNode) override
Pick the next node to schedule, or return NULL.
void pickNodeFromQueue(SchedBoundary &Zone, const CandPolicy &ZonePolicy, const RegPressureTracker &RPTracker, SchedCandidate &Cand, bool &PickedPending, bool IsBottomUp)
void initialize(ScheduleDAGMI *DAG) override
Initialize the strategy after building the DAG for a new region.
void schedNode(SUnit *SU, bool IsTopNode) override
Notify MachineSchedStrategy that ScheduleDAGMI has scheduled an instruction and updated scheduled/rem...
AMDGPUCoExecSchedStrategy(const MachineSchedContext *C)
void dumpPickSummary(SUnit *SU, bool IsTopNode, SchedCandidate &Cand)
bool tryCandidateCoexec(SchedCandidate &Cand, SchedCandidate &TryCand, SchedBoundary *Zone)
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
void updateForScheduling(SUnit *SU)
Update the state to reflect that SU is going to be scheduled.
unsigned getCarriedLatency(SUnit *SU)
Estimate the block carried latency from loads for a given SU.
HardwareUnitInfo * getHWUIFromFlavor(AMDGPU::InstructionFlavor Flavor)
Given a Flavor , find the corresponding HardwareUnit.
DenseMap< MachineInstr *, unsigned > CarriedLatencies
StallCosts getStallCosts(SUnit *SU, SchedBoundary &Zone)
void sortHWUIResources()
Sort the HardwarUnitInfo vector.
void collectRegionSummary()
Walk over the region and collect characteristics for the various heuristics.
bool tryCriticalResource(GenericSchedulerBase::SchedCandidate &TryCand, GenericSchedulerBase::SchedCandidate &Cand, SchedBoundary *Zone) const
Check for critical resource consumption.
unsigned getHWUICyclesForSU(SUnit *SU)
Compute the blocking cycles for the appropriate HardwareUnit given an SU.
bool tryCriticalResourceDependency(GenericSchedulerBase::SchedCandidate &TryCand, GenericSchedulerBase::SchedCandidate &Cand, SchedBoundary *Zone) const
Check for dependencies of instructions that use prioritized HardwareUnits.
bool tryEffectiveStall(GenericSchedulerBase::SchedCandidate &TryCand, GenericSchedulerBase::SchedCandidate &Cand, SchedBoundary &Zone)
unsigned getHWUICyclesForMI(MachineInstr *MI)
Compute the blocking cycles for the appropriate HardwareUnit given an MI.
SmallVector< HardwareUnitInfo, 8 > HWUInfo
const TargetSchedModel * SchedModel
void initialize(ScheduleDAGMI *DAG, const TargetSchedModel *SchedModel, const TargetRegisterInfo *TRI)
unsigned getMaxBlockingCycles(const MCSchedClassDesc *SC, const MachineInstr *MI)
bool tryMemoryPipeline(GenericSchedulerBase::SchedCandidate &TryCand, GenericSchedulerBase::SchedCandidate &Cand, SchedBoundary &Zone)
Prioritize instructions involved the memory pipeline.
unsigned getStructuralStallCycles(SchedBoundary &Zone, SUnit *SU)
GCNDownwardRPTracker DownwardTracker
GCNSchedStrategy(const MachineSchedContext *C)
SmallVector< GCNSchedStageID, 4 > SchedStages
void schedNode(SUnit *SU, bool IsTopNode) override
Notify MachineSchedStrategy that ScheduleDAGMI has scheduled an instruction and updated scheduled/rem...
std::vector< unsigned > Pressure
void initialize(ScheduleDAGMI *DAG) override
Initialize the strategy after building the DAG for a new region.
void printCandidateDecision(const SchedCandidate &Current, const SchedCandidate &Preferred)
void initCandidate(SchedCandidate &Cand, SUnit *SU, bool AtTop, const RegPressureTracker &RPTracker, const SIRegisterInfo *SRI, unsigned SGPRPressure, unsigned VGPRPressure, unsigned AGPRPressure, bool IsBottomUp)
MachineSchedPolicy RegionPolicy
const TargetSchedModel * SchedModel
static const char * getReasonStr(GenericSchedulerBase::CandReason Reason)
const TargetRegisterInfo * TRI
SchedCandidate TopCand
Candidate last picked from Top boundary.
ScheduleDAGMILive * DAG
HardwareUnitInfo is a wrapper class which maps to some real hardware resource.
void markScheduled(SUnit *SU, unsigned BlockingCycles)
Update the state for SU being scheduled by removing it from the AllSUs and reducing its BlockingCycle...
SUnit * getNextTargetSU(bool LookDeep=false) const
void insert(SUnit *SU, unsigned BlockingCycles)
Insert the SU into AllSUs and account its BlockingCycles into the TotalCycles.
void finalizeCycles()
After we've collected all the region pressure for this HWUI, correct for any specifics of the behavio...
AMDGPU::InstructionFlavor getType() const
unsigned getBufferAvailableCycle(unsigned CurrCycle)
SUnit * getHigherPriority(SUnit *SU, SUnit *Other) const
int getNumber() const
MachineBasicBlocks are uniquely numbered at the function level, unless they're not in a MachineFuncti...
MachineInstrBundleIterator< MachineInstr > iterator
Representation of each machine instruction.
LLVM_ABI void print(raw_ostream &OS, bool IsStandalone=true, bool SkipOpers=false, bool SkipDebugLoc=false, bool AddNewLine=true, const TargetInstrInfo *TII=nullptr) const
Print this MI to OS.
MachineOperand class - Representation of each machine instruction operand.
virtual void initPolicy(MachineBasicBlock::iterator Begin, MachineBasicBlock::iterator End, unsigned NumRegionInstrs)
Optionally override the per-region scheduling policy.
Helpers for implementing custom MachineSchedStrategy classes.
Track the current register pressure at some position in the instruction stream, and remember the high...
const std::vector< unsigned > & getRegSetPressureAtPos() const
Get the register set pressure at the current position, which may be less than the pressure across the...
static bool isDS(const MachineInstr &MI)
static bool isVMEM(const MachineInstr &MI)
static bool isSMRD(const MachineInstr &MI)
static bool isSALU(const MachineInstr &MI)
static bool isSWMMAC(const MachineInstr &MI)
unsigned getBlockingCycles(const MachineInstr &MI) const
static bool isVALU(const MachineInstr &MI, bool AllowLDSDMA)
static bool isTRANS(const MachineInstr &MI)
static bool isWaitcnt(unsigned Opcode)
static bool isMFMA(const MachineInstr &MI)
static bool isWMMA(const MachineInstr &MI)
static bool isLDSDMA(const MachineInstr &MI)
Scheduling unit. This is a node in the scheduling DAG.
unsigned TopReadyCycle
Cycle relative to start when node is ready.
unsigned NodeNum
Entry # of node in the node vector.
unsigned getHeight() const
Returns the height of this node, which is the length of the maximum path down to any node which has n...
unsigned getDepth() const
Returns the depth of this node, which is the length of the maximum path up to any node which has no p...
bool isScheduled
True once scheduled.
unsigned ParentClusterIdx
The parent cluster id.
bool hasReservedResource
Uses a reserved resource.
bool isBottomReady() const
bool isTopReady() const
MachineInstr * getInstr() const
Returns the representative MachineInstr for this SUnit.
Each Scheduling boundary is associated with ready queues.
LLVM_ABI unsigned getLatencyStallCycles(SUnit *SU)
Get the difference between the given SUnit's ready time and the current cycle.
LLVM_ABI SUnit * pickOnlyChoice()
Call this before applying any other heuristics to the Available queue.
unsigned getCurrCycle() const
Number of cycles to issue the instructions scheduled in this zone.
std::unique_ptr< ScheduleHazardRecognizer > HazardRec
LLVM_ABI std::pair< unsigned, unsigned > getNextResourceCycle(const MCSchedClassDesc *SC, unsigned PIdx, unsigned ReleaseAtCycle, unsigned AcquireAtCycle)
Compute the next cycle at which the given processor resource can be scheduled.
A ScheduleDAG for scheduling lists of MachineInstr.
ScheduleDAGMILive is an implementation of ScheduleDAGInstrs that schedules machine instructions while...
ScheduleDAGMI is an implementation of ScheduleDAGInstrs that simply schedules machine instructions ac...
void addMutation(std::unique_ptr< ScheduleDAGMutation > Mutation)
Add a postprocessing step to the DAG builder.
SlotIndex - An opaque wrapper around machine indexes.
Definition SlotIndexes.h:66
static bool isEarlierInstr(SlotIndex A, SlotIndex B)
isEarlierInstr - Return true if A refers to an instruction earlier than B.
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
Provide an instruction scheduling machine model to CodeGen passes.
const MCWriteProcResEntry * ProcResIter
A Use represents the edge between a Value definition and its users.
Definition Use.h:35
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
InstructionFlavor
Classification of instructions by execution characteristics.
constexpr unsigned MaxCoExecStages
Max stages: INT8 16x16x64 = 17 cycles, round up for safety.
CoExecInfo getMFMACoExecInfo(unsigned Opcode)
Get co-execution info for a gfx950 MFMA instruction.
CoExecMask CoExecMaskT
constexpr StringRef getFlavorName(InstructionFlavor F)
InstructionFlavor classifyFlavor(const MachineInstr &MI, const SIInstrInfo &SII)
Classify MI into the execution flavor that drives both the scheduler's slot preferences and the hazar...
StringRef getReasonName(AMDGPUSchedReason R)
ValuesClass values(OptsTy... Options)
Helper to build a ValuesClass by forwarding a variable number of arguments as an initializer list to ...
initializer< Ty > init(const Ty &Val)
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI int biasPhysReg(const SUnit *SU, bool isTop, bool BiasPRegsExtra=false)
Minimize physical register live ranges.
std::unique_ptr< ScheduleDAGMutation > createAMDGPUBarrierLatencyDAGMutation(MachineFunction *MF)
LLVM_ABI unsigned getWeakLeft(const SUnit *SU, bool isTop)
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
std::unique_ptr< ScheduleDAGMutation > createIGroupLPDAGMutation(AMDGPU::SchedulingPhase Phase)
Phase specifes whether or not this is a reentry into the IGroupLPDAGMutation.
LLVM_ABI bool tryPressure(const PressureChange &TryP, const PressureChange &CandP, GenericSchedulerBase::SchedCandidate &TryCand, GenericSchedulerBase::SchedCandidate &Cand, GenericSchedulerBase::CandReason Reason, const TargetRegisterInfo *TRI, const MachineFunction &MF)
void sort(IteratorTy Start, IteratorTy End)
Definition STLExtras.h:1652
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
cl::opt< unsigned, false, VGPRThresholdParser > VGPRThresholdPercentOpt
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:163
ScheduleDAGInstrs * createGCNNoopPostMachineScheduler(MachineSchedContext *C)
LLVM_ABI bool tryLatency(GenericSchedulerBase::SchedCandidate &TryCand, GenericSchedulerBase::SchedCandidate &Cand, SchedBoundary &Zone)
ScheduleDAGInstrs * createGCNCoExecMachineScheduler(MachineSchedContext *C)
bool isTheSameCluster(unsigned A, unsigned B)
Return whether the input cluster ID's are the same and valid.
DWARFExpression::Operation Op
LLVM_ABI bool tryGreater(int TryVal, int CandVal, GenericSchedulerBase::SchedCandidate &TryCand, GenericSchedulerBase::SchedCandidate &Cand, GenericSchedulerBase::CandReason Reason)
LLVM_ABI bool tryLess(int TryVal, int CandVal, GenericSchedulerBase::SchedCandidate &TryCand, GenericSchedulerBase::SchedCandidate &Cand, GenericSchedulerBase::CandReason Reason)
Return true if this heuristic determines order.
@ Enabled
Convert any .debug_str_offsets tables to DWARF64 if needed.
Definition DWP.h:31
LLVM_ABI cl::opt< MISched::Direction > PreRADirection
Co-execution characteristics for a multi-cycle instruction.
unsigned TotalWindow
Number of cycles in the co-execution window, counting any trailing vacant stages.
StringRef Pattern
Pattern string for display (e.g., "0EIIEEIIV").
static CoExecInfo build(unsigned UnitOccupancy, unsigned TotalWindow, const char *Pattern)
Build a CoExecInfo from an occupancy and stage pattern.
CoExecSlotInfo Slots[MaxCoExecStages]
Per-stage slot info (capability mask).
Policy for scheduling the next instruction in the candidate's zone.
Store the state used by GenericScheduler heuristics, required for the lifetime of one invocation of p...
LLVM_ABI void initResourceDelta(const ScheduleDAGMI *DAG, const TargetSchedModel *SchedModel)
Status of an instruction's critical resource consumption.
Summarize the scheduling resources required for an instruction of a particular scheduling class.
Definition MCSchedule.h:129
Identify one of the processor resource kinds consumed by a particular scheduling class for the specif...
Definition MCSchedule.h:74
MachineSchedContext provides enough context from the MachineScheduler pass for the target to instanti...