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 printSWaitcntImm(Imm, OS);
95 break;
96 case AMDGPU::S_WAITCNT_DEPCTR:
97 printSWaitAluImm(Imm, OS);
98 break;
99 case AMDGPU::S_DELAY_ALU:
100 assert(OpIdx == 0);
101 printSDelayAluImm(Imm, OS);
102 break;
103 default:
105 break;
106 }
107}
108
109/// Implement target specific parsing of immediate mnemonics. The mnemonic is
110/// a string with a leading dot.
111bool AMDGPUMIRFormatter::parseImmMnemonic(const unsigned OpCode,
112 const unsigned OpIdx,
113 StringRef Src, int64_t &Imm,
114 ErrorCallbackType ErrorCallback) const
115{
116
117 switch (OpCode) {
118 case AMDGPU::S_WAITCNT:
119 return parseSWaitcntImmMnemonic(OpIdx, Imm, Src, ErrorCallback);
120 case AMDGPU::S_WAITCNT_DEPCTR:
121 return parseSWaitAluImmMnemonic(OpIdx, Imm, Src, ErrorCallback);
122 case AMDGPU::S_DELAY_ALU:
123 return parseSDelayAluImmMnemonic(OpIdx, Imm, Src, ErrorCallback);
124 default:
125 break;
126 }
127 return true; // Don't know what this is
128}
129
130void AMDGPUMIRFormatter::printSDelayAluImm(int64_t Imm,
131 llvm::raw_ostream &OS) const {
132 // Construct an immediate string to represent the information encoded in the
133 // s_delay_alu immediate.
134 // .id0_<dep>[_skip_<count>_id1<dep>]
135 constexpr int64_t None = 0;
136 constexpr int64_t Same = 0;
137
138 uint64_t Id0 = (Imm & 0xF);
139 uint64_t Skip = ((Imm >> 4) & 0x7);
140 uint64_t Id1 = ((Imm >> 7) & 0xF);
141 auto Outdep = [&](uint64_t Id) {
142 if (Id == None)
143 OS << "NONE";
144 else if (Id < 5)
145 OS << "VALU_DEP_" << Id;
146 else if (Id < 8)
147 OS << "TRANS32_DEP_" << Id - 4;
148 else
149 OS << "SALU_CYCLE_" << Id - 8;
150 };
151
152 OS << ".id0_";
153 Outdep(Id0);
154
155 // If the second inst is "same" and "none", no need to print the rest of the
156 // string.
157 if (Skip == Same && Id1 == None)
158 return;
159
160 // Encode the second delay specification.
161 OS << "_skip_";
162 if (Skip == 0)
163 OS << "SAME";
164 else if (Skip == 1)
165 OS << "NEXT";
166 else
167 OS << "SKIP_" << Skip - 1;
168
169 OS << "_id1_";
170 Outdep(Id1);
171}
172
173bool AMDGPUMIRFormatter::parseSWaitcntImmMnemonic(
174 const unsigned int OpIdx, int64_t &Imm, StringRef &Src,
175 MIRFormatter::ErrorCallbackType &ErrorCallback) const {
176 const AMDGPU::IsaVersion &Version = AMDGPU::getIsaVersion(STI.getCPU());
177
178 // Accept integer masks for compatibility with old MIR.
179 if (!Src.consumeInteger(10, Imm))
180 return false;
181
182 // Initialize with all counters at max (no wait).
183 unsigned Vmcnt = AMDGPU::getVmcntBitMask(Version);
184 unsigned Expcnt = AMDGPU::getExpcntBitMask(Version);
185 unsigned Lgkmcnt = AMDGPU::getLgkmcntBitMask(Version);
186
187 // The input is in the form: .Name1_Num1_Name2_Num2
188 // Drop the '.' prefix.
189 if (!Src.consume_front(SWaitAluImmPrefix))
190 return ErrorCallback(Src.begin(), "expected prefix");
191 if (Src.empty())
192 return ErrorCallback(Src.begin(), "expected <CounterName>_<CounterNum>");
193
194 // Special case for all off (all counters at max).
195 if (Src == AllOff) {
196 Imm = AMDGPU::encodeWaitcnt(Version, Vmcnt, Expcnt, Lgkmcnt);
197 return false;
198 }
199
200 // Parse counter name, number pairs.
201 while (!Src.empty()) {
202 size_t DelimIdx = Src.find(SWaitAluDelim);
203 if (DelimIdx == StringRef::npos)
204 return ErrorCallback(Src.begin(), "expected <CounterName>_<CounterNum>");
205 StringRef Name = Src.substr(0, DelimIdx);
206 StringRef::iterator NamePos = Src.begin();
207 Src.consume_front(Name);
208 Src.consume_front(SWaitAluDelim);
209
210 int64_t Num;
211 StringRef::iterator NumPos = Src.begin();
212 if (Src.consumeInteger(10, Num) || Num < 0)
213 return ErrorCallback(NumPos,
214 "expected non-negative integer counter number");
215
216 unsigned Max;
217 if (Name == VmcntName) {
219 Vmcnt = Num;
220 } else if (Name == ExpcntName) {
222 Expcnt = Num;
223 } else if (Name == LgkmcntName) {
225 Lgkmcnt = Num;
226 } else {
227 return ErrorCallback(NamePos, "invalid counter name");
228 }
229 if (Num >= Max)
230 return ErrorCallback(NumPos, "counter value too large");
231
232 Src.consume_front(SWaitAluDelim);
233 }
234
235 Imm = AMDGPU::encodeWaitcnt(Version, Vmcnt, Expcnt, Lgkmcnt);
236 return false;
237}
238
239bool AMDGPUMIRFormatter::parseSWaitAluImmMnemonic(
240 const unsigned int OpIdx, int64_t &Imm, StringRef &Src,
241 MIRFormatter::ErrorCallbackType &ErrorCallback) const {
242 // TODO: For now accept integer masks for compatibility with old MIR.
243 if (!Src.consumeInteger(10, Imm))
244 return false;
245
246 // Initialize with all checks off.
248 // The input is in the form: .Name1_Num1_Name2_Num2
249 // Drop the '.' prefix.
250 bool ConsumePrefix = Src.consume_front(SWaitAluImmPrefix);
251 if (!ConsumePrefix)
252 return ErrorCallback(Src.begin(), "expected prefix");
253 if (Src.empty())
254 return ErrorCallback(Src.begin(), "expected <CounterName>_<CounterNum>");
255
256 // Special case for all off.
257 if (Src == AllOff)
258 return false;
259
260 // Parse a counter name, number pair in each iteration.
261 while (!Src.empty()) {
262 // Src: Name1_Num1_Name2_Num2
263 // ^
264 size_t DelimIdx = Src.find(SWaitAluDelim);
265 if (DelimIdx == StringRef::npos)
266 return ErrorCallback(Src.begin(), "expected <CounterName>_<CounterNum>");
267 // Src: Name1_Num1_Name2_Num2
268 // ^^^^^
269 StringRef Name = Src.substr(0, DelimIdx);
270 // Save the position of the name for accurate error reporting.
271 StringRef::iterator NamePos = Src.begin();
272 [[maybe_unused]] bool ConsumeName = Src.consume_front(Name);
273 assert(ConsumeName && "Expected name");
274 [[maybe_unused]] bool ConsumeDelim = Src.consume_front(SWaitAluDelim);
275 assert(ConsumeDelim && "Expected delimiter");
276 // Src: Num1_Name2_Num2
277 // ^
278 DelimIdx = Src.find(SWaitAluDelim);
279 // Src: Num1_Name2_Num2
280 // ^^^^
281 int64_t Num;
282 // Save the position of the number for accurate error reporting.
283 StringRef::iterator NumPos = Src.begin();
284 if (Src.consumeInteger(10, Num) || Num < 0)
285 return ErrorCallback(NumPos,
286 "expected non-negative integer counter number");
287 unsigned Max;
288 if (Name == VaVdstName) {
291 } else if (Name == VmVsrcName) {
294 } else if (Name == VaSdstName) {
297 } else if (Name == VaSsrcName) {
300 } else if (Name == HoldCntName) {
301 const AMDGPU::IsaVersion &Version = AMDGPU::getIsaVersion(STI.getCPU());
304 } else if (Name == VaVccName) {
307 } else if (Name == SaSdstName) {
310 } else {
311 return ErrorCallback(NamePos, "invalid counter name");
312 }
313 // Don't allow the values to reach their maximum value.
314 if (Num >= Max)
315 return ErrorCallback(NumPos, "counter value too large");
316 // Src: Name2_Num2
317 Src.consume_front(SWaitAluDelim);
318 }
319 return false;
320}
321
322bool AMDGPUMIRFormatter::parseSDelayAluImmMnemonic(
323 const unsigned int OpIdx, int64_t &Imm, llvm::StringRef &Src,
324 llvm::MIRFormatter::ErrorCallbackType &ErrorCallback) const
325{
326 assert(OpIdx == 0);
327
328 Imm = 0;
329 bool Expected = Src.consume_front(".id0_");
330 if (!Expected)
331 return ErrorCallback(Src.begin(), "Expected .id0_");
332
333 auto ExpectInt = [&](StringRef &Src, int64_t Offset) -> int64_t {
334 int64_t Dep;
335 if (!Src.consumeInteger(10, Dep))
336 return Dep + Offset;
337
338 return -1;
339 };
340
341 auto DecodeDelay = [&](StringRef &Src) -> int64_t {
342 if (Src.consume_front("NONE"))
343 return 0;
344 if (Src.consume_front("VALU_DEP_"))
345 return ExpectInt(Src, 0);
346 if (Src.consume_front("TRANS32_DEP_"))
347 return ExpectInt(Src, 4);
348 if (Src.consume_front("SALU_CYCLE_"))
349 return ExpectInt(Src, 8);
350
351 return -1;
352 };
353
354 int64_t Delay0 = DecodeDelay(Src);
355 int64_t Skip = 0;
356 int64_t Delay1 = 0;
357 if (Delay0 == -1)
358 return ErrorCallback(Src.begin(), "Could not decode delay0");
359
360
361 // Set the Imm so far, to that early return has the correct value.
362 Imm = Delay0;
363
364 // If that was the end of the string, the second instruction is "same" and
365 // "none"
366 if (Src.begin() == Src.end())
367 return false;
368
369 Expected = Src.consume_front("_skip_");
370 if (!Expected)
371 return ErrorCallback(Src.begin(), "Expected _skip_");
372
373
374 if (Src.consume_front("SAME")) {
375 Skip = 0;
376 } else if (Src.consume_front("NEXT")) {
377 Skip = 1;
378 } else if (Src.consume_front("SKIP_")) {
379 if (Src.consumeInteger(10, Skip)) {
380 return ErrorCallback(Src.begin(), "Expected integer Skip value");
381 }
382 Skip += 1;
383 } else {
384 ErrorCallback(Src.begin(), "Unexpected Skip Value");
385 }
386
387 Expected = Src.consume_front("_id1_");
388 if (!Expected)
389 return ErrorCallback(Src.begin(), "Expected _id1_");
390
391 Delay1 = DecodeDelay(Src);
392 if (Delay1 == -1)
393 return ErrorCallback(Src.begin(), "Could not decode delay1");
394
395 Imm = Imm | (Skip << 4) | (Delay1 << 7);
396 return false;
397}
398
401 const PseudoSourceValue *&PSV, ErrorCallbackType ErrorCallback) const {
403 const AMDGPUTargetMachine &TM =
404 static_cast<const AMDGPUTargetMachine &>(MF.getTarget());
405 if (Src == "GWSResource") {
406 PSV = MFI->getGWSPSV(TM);
407 return false;
408 }
409 llvm_unreachable("unknown MIR custom pseudo source value");
410}
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
StringRef - Represent a constant reference to a string, i.e.
Definition StringRef.h:55
static constexpr size_t npos
Definition StringRef.h:57
const char * iterator
Definition StringRef.h:59
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