LLVM 23.0.0git
AMDGPUMIRFormatter.cpp
Go to the documentation of this file.
1//===- AMDGPUMIRFormatter.cpp ---------------------------------------------===//
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/// Implementation of AMDGPU overrides of MIRFormatter.
11//
12//===----------------------------------------------------------------------===//
13
14#include "AMDGPUMIRFormatter.h"
17
18using namespace llvm;
19
20const char SWaitAluImmPrefix = '.';
22
30
32
36
37void AMDGPUMIRFormatter::printSWaitAluImm(uint64_t Imm, raw_ostream &OS) const {
38 bool NonePrinted = true;
40 auto PrintFieldIfNotMax = [&](StringRef Descr, uint64_t Num, unsigned Max) {
41 if (Num != Max) {
42 OS << Delim << Descr << SWaitAluDelim << Num;
43 NonePrinted = false;
44 }
45 };
47 PrintFieldIfNotMax(VaVdstName, AMDGPU::DepCtr::decodeFieldVaVdst(Imm),
49 PrintFieldIfNotMax(VaSdstName, AMDGPU::DepCtr::decodeFieldVaSdst(Imm),
51 PrintFieldIfNotMax(VaSsrcName, AMDGPU::DepCtr::decodeFieldVaSsrc(Imm),
53 PrintFieldIfNotMax(
58 PrintFieldIfNotMax(VmVsrcName, AMDGPU::DepCtr::decodeFieldVmVsrc(Imm),
60 PrintFieldIfNotMax(VaVccName, AMDGPU::DepCtr::decodeFieldVaVcc(Imm),
62 PrintFieldIfNotMax(SaSdstName, AMDGPU::DepCtr::decodeFieldSaSdst(Imm),
64 if (NonePrinted)
65 OS << AllOff;
66}
67
68void AMDGPUMIRFormatter::printSWaitcntImm(uint64_t Imm, raw_ostream &OS) const {
69 const AMDGPU::IsaVersion &Version = AMDGPU::getIsaVersion(STI.getCPU());
70 bool NonePrinted = true;
71 ListSeparator Delim(SWaitAluDelim);
72 auto PrintFieldIfNotMax = [&](StringRef Descr, uint64_t Num, unsigned Max) {
73 if (Num != Max) {
74 OS << Delim << Descr << SWaitAluDelim << Num;
75 NonePrinted = false;
76 }
77 };
79 PrintFieldIfNotMax(VmcntName, AMDGPU::decodeVmcnt(Version, Imm),
81 PrintFieldIfNotMax(ExpcntName, AMDGPU::decodeExpcnt(Version, Imm),
83 PrintFieldIfNotMax(LgkmcntName, AMDGPU::decodeLgkmcnt(Version, Imm),
85 if (NonePrinted)
86 OS << AllOff;
87}
88
90 std::optional<unsigned int> OpIdx, int64_t Imm) const {
91
92 switch (MI.getOpcode()) {
93 case AMDGPU::S_WAITCNT:
94 case AMDGPU::S_WAITCNT_soft:
95 printSWaitcntImm(Imm, OS);
96 break;
97 case AMDGPU::S_WAITCNT_DEPCTR:
98 printSWaitAluImm(Imm, OS);
99 break;
100 case AMDGPU::S_DELAY_ALU:
101 assert(OpIdx == 0);
102 printSDelayAluImm(Imm, OS);
103 break;
104 default:
106 break;
107 }
108}
109
110/// Implement target specific parsing of immediate mnemonics. The mnemonic is
111/// a string with a leading dot.
112bool AMDGPUMIRFormatter::parseImmMnemonic(const unsigned OpCode,
113 const unsigned OpIdx,
114 StringRef Src, int64_t &Imm,
115 ErrorCallbackType ErrorCallback) const
116{
117
118 switch (OpCode) {
119 case AMDGPU::S_WAITCNT:
120 case AMDGPU::S_WAITCNT_soft:
121 return parseSWaitcntImmMnemonic(OpIdx, Imm, Src, ErrorCallback);
122 case AMDGPU::S_WAITCNT_DEPCTR:
123 return parseSWaitAluImmMnemonic(OpIdx, Imm, Src, ErrorCallback);
124 case AMDGPU::S_DELAY_ALU:
125 return parseSDelayAluImmMnemonic(OpIdx, Imm, Src, ErrorCallback);
126 default:
127 break;
128 }
129 return true; // Don't know what this is
130}
131
132void AMDGPUMIRFormatter::printSDelayAluImm(int64_t Imm,
133 llvm::raw_ostream &OS) const {
134 // Construct an immediate string to represent the information encoded in the
135 // s_delay_alu immediate.
136 // .id0_<dep>[_skip_<count>_id1<dep>]
137 constexpr int64_t None = 0;
138 constexpr int64_t Same = 0;
139
140 uint64_t Id0 = (Imm & 0xF);
141 uint64_t Skip = ((Imm >> 4) & 0x7);
142 uint64_t Id1 = ((Imm >> 7) & 0xF);
143 auto Outdep = [&](uint64_t Id) {
144 if (Id == None)
145 OS << "NONE";
146 else if (Id < 5)
147 OS << "VALU_DEP_" << Id;
148 else if (Id < 8)
149 OS << "TRANS32_DEP_" << Id - 4;
150 else
151 OS << "SALU_CYCLE_" << Id - 8;
152 };
153
154 OS << ".id0_";
155 Outdep(Id0);
156
157 // If the second inst is "same" and "none", no need to print the rest of the
158 // string.
159 if (Skip == Same && Id1 == None)
160 return;
161
162 // Encode the second delay specification.
163 OS << "_skip_";
164 if (Skip == 0)
165 OS << "SAME";
166 else if (Skip == 1)
167 OS << "NEXT";
168 else
169 OS << "SKIP_" << Skip - 1;
170
171 OS << "_id1_";
172 Outdep(Id1);
173}
174
175bool AMDGPUMIRFormatter::parseSWaitcntImmMnemonic(
176 const unsigned int OpIdx, int64_t &Imm, StringRef &Src,
177 MIRFormatter::ErrorCallbackType &ErrorCallback) const {
178 const AMDGPU::IsaVersion &Version = AMDGPU::getIsaVersion(STI.getCPU());
179
180 // Accept integer masks for compatibility with old MIR.
181 if (!Src.consumeInteger(10, Imm))
182 return false;
183
184 // Initialize with all counters at max (no wait).
185 unsigned Vmcnt = AMDGPU::getVmcntBitMask(Version);
186 unsigned Expcnt = AMDGPU::getExpcntBitMask(Version);
187 unsigned Lgkmcnt = AMDGPU::getLgkmcntBitMask(Version);
188
189 // The input is in the form: .Name1_Num1_Name2_Num2
190 // Drop the '.' prefix.
191 if (!Src.consume_front(SWaitAluImmPrefix))
192 return ErrorCallback(Src.begin(), "expected prefix");
193 if (Src.empty())
194 return ErrorCallback(Src.begin(), "expected <CounterName>_<CounterNum>");
195
196 // Special case for all off (all counters at max).
197 if (Src == AllOff) {
198 Imm = AMDGPU::encodeWaitcnt(Version, Vmcnt, Expcnt, Lgkmcnt);
199 return false;
200 }
201
202 // Parse counter name, number pairs.
203 while (!Src.empty()) {
204 size_t DelimIdx = Src.find(SWaitAluDelim);
205 if (DelimIdx == StringRef::npos)
206 return ErrorCallback(Src.begin(), "expected <CounterName>_<CounterNum>");
207 StringRef Name = Src.substr(0, DelimIdx);
208 StringRef::iterator NamePos = Src.begin();
209 Src.consume_front(Name);
210 Src.consume_front(SWaitAluDelim);
211
212 int64_t Num;
213 StringRef::iterator NumPos = Src.begin();
214 if (Src.consumeInteger(10, Num) || Num < 0)
215 return ErrorCallback(NumPos,
216 "expected non-negative integer counter number");
217
218 unsigned Max;
219 if (Name == VmcntName) {
221 Vmcnt = Num;
222 } else if (Name == ExpcntName) {
224 Expcnt = Num;
225 } else if (Name == LgkmcntName) {
227 Lgkmcnt = Num;
228 } else {
229 return ErrorCallback(NamePos, "invalid counter name");
230 }
231 if (Num >= Max)
232 return ErrorCallback(NumPos, "counter value too large");
233
234 Src.consume_front(SWaitAluDelim);
235 }
236
237 Imm = AMDGPU::encodeWaitcnt(Version, Vmcnt, Expcnt, Lgkmcnt);
238 return false;
239}
240
241bool AMDGPUMIRFormatter::parseSWaitAluImmMnemonic(
242 const unsigned int OpIdx, int64_t &Imm, StringRef &Src,
243 MIRFormatter::ErrorCallbackType &ErrorCallback) const {
244 // TODO: For now accept integer masks for compatibility with old MIR.
245 if (!Src.consumeInteger(10, Imm))
246 return false;
247
248 // Initialize with all checks off.
250 // The input is in the form: .Name1_Num1_Name2_Num2
251 // Drop the '.' prefix.
252 bool ConsumePrefix = Src.consume_front(SWaitAluImmPrefix);
253 if (!ConsumePrefix)
254 return ErrorCallback(Src.begin(), "expected prefix");
255 if (Src.empty())
256 return ErrorCallback(Src.begin(), "expected <CounterName>_<CounterNum>");
257
258 // Special case for all off.
259 if (Src == AllOff)
260 return false;
261
262 // Parse a counter name, number pair in each iteration.
263 while (!Src.empty()) {
264 // Src: Name1_Num1_Name2_Num2
265 // ^
266 size_t DelimIdx = Src.find(SWaitAluDelim);
267 if (DelimIdx == StringRef::npos)
268 return ErrorCallback(Src.begin(), "expected <CounterName>_<CounterNum>");
269 // Src: Name1_Num1_Name2_Num2
270 // ^^^^^
271 StringRef Name = Src.substr(0, DelimIdx);
272 // Save the position of the name for accurate error reporting.
273 StringRef::iterator NamePos = Src.begin();
274 [[maybe_unused]] bool ConsumeName = Src.consume_front(Name);
275 assert(ConsumeName && "Expected name");
276 [[maybe_unused]] bool ConsumeDelim = Src.consume_front(SWaitAluDelim);
277 assert(ConsumeDelim && "Expected delimiter");
278 // Src: Num1_Name2_Num2
279 // ^
280 DelimIdx = Src.find(SWaitAluDelim);
281 // Src: Num1_Name2_Num2
282 // ^^^^
283 int64_t Num;
284 // Save the position of the number for accurate error reporting.
285 StringRef::iterator NumPos = Src.begin();
286 if (Src.consumeInteger(10, Num) || Num < 0)
287 return ErrorCallback(NumPos,
288 "expected non-negative integer counter number");
289 unsigned Max;
290 if (Name == VaVdstName) {
293 } else if (Name == VmVsrcName) {
296 } else if (Name == VaSdstName) {
299 } else if (Name == VaSsrcName) {
302 } else if (Name == HoldCntName) {
303 const AMDGPU::IsaVersion &Version = AMDGPU::getIsaVersion(STI.getCPU());
306 } else if (Name == VaVccName) {
309 } else if (Name == SaSdstName) {
312 } else {
313 return ErrorCallback(NamePos, "invalid counter name");
314 }
315 // Don't allow the values to reach their maximum value.
316 if (Num >= Max)
317 return ErrorCallback(NumPos, "counter value too large");
318 // Src: Name2_Num2
319 Src.consume_front(SWaitAluDelim);
320 }
321 return false;
322}
323
324bool AMDGPUMIRFormatter::parseSDelayAluImmMnemonic(
325 const unsigned int OpIdx, int64_t &Imm, llvm::StringRef &Src,
326 llvm::MIRFormatter::ErrorCallbackType &ErrorCallback) const
327{
328 assert(OpIdx == 0);
329
330 Imm = 0;
331 bool Expected = Src.consume_front(".id0_");
332 if (!Expected)
333 return ErrorCallback(Src.begin(), "Expected .id0_");
334
335 auto ExpectInt = [&](StringRef &Src, int64_t Offset) -> int64_t {
336 int64_t Dep;
337 if (!Src.consumeInteger(10, Dep))
338 return Dep + Offset;
339
340 return -1;
341 };
342
343 auto DecodeDelay = [&](StringRef &Src) -> int64_t {
344 if (Src.consume_front("NONE"))
345 return 0;
346 if (Src.consume_front("VALU_DEP_"))
347 return ExpectInt(Src, 0);
348 if (Src.consume_front("TRANS32_DEP_"))
349 return ExpectInt(Src, 4);
350 if (Src.consume_front("SALU_CYCLE_"))
351 return ExpectInt(Src, 8);
352
353 return -1;
354 };
355
356 int64_t Delay0 = DecodeDelay(Src);
357 int64_t Skip = 0;
358 int64_t Delay1 = 0;
359 if (Delay0 == -1)
360 return ErrorCallback(Src.begin(), "Could not decode delay0");
361
362
363 // Set the Imm so far, to that early return has the correct value.
364 Imm = Delay0;
365
366 // If that was the end of the string, the second instruction is "same" and
367 // "none"
368 if (Src.begin() == Src.end())
369 return false;
370
371 Expected = Src.consume_front("_skip_");
372 if (!Expected)
373 return ErrorCallback(Src.begin(), "Expected _skip_");
374
375
376 if (Src.consume_front("SAME")) {
377 Skip = 0;
378 } else if (Src.consume_front("NEXT")) {
379 Skip = 1;
380 } else if (Src.consume_front("SKIP_")) {
381 if (Src.consumeInteger(10, Skip)) {
382 return ErrorCallback(Src.begin(), "Expected integer Skip value");
383 }
384 Skip += 1;
385 } else {
386 ErrorCallback(Src.begin(), "Unexpected Skip Value");
387 }
388
389 Expected = Src.consume_front("_id1_");
390 if (!Expected)
391 return ErrorCallback(Src.begin(), "Expected _id1_");
392
393 Delay1 = DecodeDelay(Src);
394 if (Delay1 == -1)
395 return ErrorCallback(Src.begin(), "Could not decode delay1");
396
397 Imm = Imm | (Skip << 4) | (Delay1 << 7);
398 return false;
399}
400
403 const PseudoSourceValue *&PSV, ErrorCallbackType ErrorCallback) const {
405 const AMDGPUTargetMachine &TM =
406 static_cast<const AMDGPUTargetMachine &>(MF.getTarget());
407 if (Src == "GWSResource") {
408 PSV = MFI->getGWSPSV(TM);
409 return false;
410 }
411 llvm_unreachable("unknown MIR custom pseudo source value");
412}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
StringLiteral VmVsrcName
StringLiteral HoldCntName
StringLiteral ExpcntName
StringLiteral AllOff
StringLiteral VaVccName
StringLiteral SWaitAluDelim
const char SWaitAluImmPrefix
StringLiteral VaSsrcName
StringLiteral LgkmcntName
StringLiteral VaSdstName
StringLiteral SaSdstName
StringLiteral VmcntName
StringLiteral VaVdstName
AMDGPU specific overrides of MIRFormatter.
IRTranslator LLVM IR MI
MachineInstr unsigned OpIdx
bool parseCustomPseudoSourceValue(StringRef Src, MachineFunction &MF, PerFunctionMIParsingState &PFS, const PseudoSourceValue *&PSV, ErrorCallbackType ErrorCallback) const override
Implement target specific parsing of target custom pseudo source value.
void printImm(raw_ostream &OS, const MachineInstr &MI, std::optional< unsigned > OpIdx, int64_t Imm) const override
Implement target specific printing for machine operand immediate value, so that we can have more mean...
bool parseImmMnemonic(const unsigned OpCode, const unsigned OpIdx, StringRef Src, int64_t &Imm, ErrorCallbackType ErrorCallback) const override
Implement target specific parsing of immediate mnemonics.
A helper class to return the specified delimiter string after the first invocation of operator String...
StringRef getCPU() const
function_ref< bool(StringRef::iterator Loc, const Twine &)> ErrorCallbackType
virtual void printImm(raw_ostream &OS, const MachineInstr &MI, std::optional< unsigned > OpIdx, int64_t Imm) const
Implement target specific printing for machine operand immediate value, so that we can have more mean...
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
const TargetMachine & getTarget() const
getTarget - Return the target machine this machine code is compiled with
Representation of each machine instruction.
Special value supplied for machine level alias analysis.
This class keeps track of the SPI_SP_INPUT_ADDR config register, which tells the hardware which inter...
const AMDGPUGWSResourcePseudoSourceValue * getGWSPSV(const AMDGPUTargetMachine &TM)
A wrapper around a string literal that serves as a proxy for constructing global tables of StringRefs...
Definition StringRef.h:882
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
static constexpr size_t npos
Definition StringRef.h:58
const char * iterator
Definition StringRef.h:60
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition raw_ostream.h:53
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
unsigned decodeFieldVaVcc(unsigned Encoded)
unsigned encodeFieldVaVcc(unsigned Encoded, unsigned VaVcc)
unsigned decodeFieldHoldCnt(unsigned Encoded, const IsaVersion &Version)
unsigned encodeFieldHoldCnt(unsigned Encoded, unsigned HoldCnt, const IsaVersion &Version)
unsigned encodeFieldVaSsrc(unsigned Encoded, unsigned VaSsrc)
unsigned encodeFieldVaVdst(unsigned Encoded, unsigned VaVdst)
unsigned decodeFieldSaSdst(unsigned Encoded)
unsigned getHoldCntBitMask(const IsaVersion &Version)
unsigned decodeFieldVaSdst(unsigned Encoded)
unsigned encodeFieldVmVsrc(unsigned Encoded, unsigned VmVsrc)
unsigned decodeFieldVaSsrc(unsigned Encoded)
unsigned encodeFieldSaSdst(unsigned Encoded, unsigned SaSdst)
unsigned decodeFieldVaVdst(unsigned Encoded)
int getDefaultDepCtrEncoding(const MCSubtargetInfo &STI)
unsigned decodeFieldVmVsrc(unsigned Encoded)
unsigned encodeFieldVaSdst(unsigned Encoded, unsigned VaSdst)
LLVM_ABI IsaVersion getIsaVersion(StringRef GPU)
unsigned encodeWaitcnt(const IsaVersion &Version, const Waitcnt &Decoded)
unsigned decodeLgkmcnt(const IsaVersion &Version, unsigned Waitcnt)
unsigned getVmcntBitMask(const IsaVersion &Version)
unsigned getLgkmcntBitMask(const IsaVersion &Version)
unsigned getExpcntBitMask(const IsaVersion &Version)
unsigned decodeExpcnt(const IsaVersion &Version, unsigned Waitcnt)
unsigned decodeVmcnt(const IsaVersion &Version, unsigned Waitcnt)
This is an optimization pass for GlobalISel generic memory operations.
@ Offset
Definition DWP.cpp:557
FunctionAddr VTableAddr uintptr_t uintptr_t Version
Definition InstrProf.h:334