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
33void AMDGPUMIRFormatter::printSWaitAluImm(uint64_t Imm, raw_ostream &OS) const {
34 bool NonePrinted = true;
36 auto PrintFieldIfNotMax = [&](StringRef Descr, uint64_t Num, unsigned Max) {
37 if (Num != Max) {
38 OS << Delim << Descr << SWaitAluDelim << Num;
39 NonePrinted = false;
40 }
41 };
43 PrintFieldIfNotMax(VaVdstName, AMDGPU::DepCtr::decodeFieldVaVdst(Imm),
45 PrintFieldIfNotMax(VaSdstName, AMDGPU::DepCtr::decodeFieldVaSdst(Imm),
47 PrintFieldIfNotMax(VaSsrcName, AMDGPU::DepCtr::decodeFieldVaSsrc(Imm),
49 PrintFieldIfNotMax(
54 PrintFieldIfNotMax(VmVsrcName, AMDGPU::DepCtr::decodeFieldVmVsrc(Imm),
56 PrintFieldIfNotMax(VaVccName, AMDGPU::DepCtr::decodeFieldVaVcc(Imm),
58 PrintFieldIfNotMax(SaSdstName, AMDGPU::DepCtr::decodeFieldSaSdst(Imm),
60 if (NonePrinted)
61 OS << AllOff;
62}
63
65 std::optional<unsigned int> OpIdx, int64_t Imm) const {
66
67 switch (MI.getOpcode()) {
68 case AMDGPU::S_WAITCNT_DEPCTR:
69 printSWaitAluImm(Imm, OS);
70 break;
71 case AMDGPU::S_DELAY_ALU:
72 assert(OpIdx == 0);
73 printSDelayAluImm(Imm, OS);
74 break;
75 default:
77 break;
78 }
79}
80
81/// Implement target specific parsing of immediate mnemonics. The mnemonic is
82/// a string with a leading dot.
83bool AMDGPUMIRFormatter::parseImmMnemonic(const unsigned OpCode,
84 const unsigned OpIdx,
85 StringRef Src, int64_t &Imm,
86 ErrorCallbackType ErrorCallback) const
87{
88
89 switch (OpCode) {
90 case AMDGPU::S_WAITCNT_DEPCTR:
91 return parseSWaitAluImmMnemonic(OpIdx, Imm, Src, ErrorCallback);
92 case AMDGPU::S_DELAY_ALU:
93 return parseSDelayAluImmMnemonic(OpIdx, Imm, Src, ErrorCallback);
94 default:
95 break;
96 }
97 return true; // Don't know what this is
98}
99
100void AMDGPUMIRFormatter::printSDelayAluImm(int64_t Imm,
101 llvm::raw_ostream &OS) const {
102 // Construct an immediate string to represent the information encoded in the
103 // s_delay_alu immediate.
104 // .id0_<dep>[_skip_<count>_id1<dep>]
105 constexpr int64_t None = 0;
106 constexpr int64_t Same = 0;
107
108 uint64_t Id0 = (Imm & 0xF);
109 uint64_t Skip = ((Imm >> 4) & 0x7);
110 uint64_t Id1 = ((Imm >> 7) & 0xF);
111 auto Outdep = [&](uint64_t Id) {
112 if (Id == None)
113 OS << "NONE";
114 else if (Id < 5)
115 OS << "VALU_DEP_" << Id;
116 else if (Id < 8)
117 OS << "TRANS32_DEP_" << Id - 4;
118 else
119 OS << "SALU_CYCLE_" << Id - 8;
120 };
121
122 OS << ".id0_";
123 Outdep(Id0);
124
125 // If the second inst is "same" and "none", no need to print the rest of the
126 // string.
127 if (Skip == Same && Id1 == None)
128 return;
129
130 // Encode the second delay specification.
131 OS << "_skip_";
132 if (Skip == 0)
133 OS << "SAME";
134 else if (Skip == 1)
135 OS << "NEXT";
136 else
137 OS << "SKIP_" << Skip - 1;
138
139 OS << "_id1_";
140 Outdep(Id1);
141}
142
143bool AMDGPUMIRFormatter::parseSWaitAluImmMnemonic(
144 const unsigned int OpIdx, int64_t &Imm, StringRef &Src,
145 MIRFormatter::ErrorCallbackType &ErrorCallback) const {
146 // TODO: For now accept integer masks for compatibility with old MIR.
147 if (!Src.consumeInteger(10, Imm))
148 return false;
149
150 // Initialize with all checks off.
152 // The input is in the form: .Name1_Num1_Name2_Num2
153 // Drop the '.' prefix.
154 bool ConsumePrefix = Src.consume_front(SWaitAluImmPrefix);
155 if (!ConsumePrefix)
156 return ErrorCallback(Src.begin(), "expected prefix");
157 if (Src.empty())
158 return ErrorCallback(Src.begin(), "expected <CounterName>_<CounterNum>");
159
160 // Special case for all off.
161 if (Src == AllOff)
162 return false;
163
164 // Parse a counter name, number pair in each iteration.
165 while (!Src.empty()) {
166 // Src: Name1_Num1_Name2_Num2
167 // ^
168 size_t DelimIdx = Src.find(SWaitAluDelim);
169 if (DelimIdx == StringRef::npos)
170 return ErrorCallback(Src.begin(), "expected <CounterName>_<CounterNum>");
171 // Src: Name1_Num1_Name2_Num2
172 // ^^^^^
173 StringRef Name = Src.substr(0, DelimIdx);
174 // Save the position of the name for accurate error reporting.
175 StringRef::iterator NamePos = Src.begin();
176 [[maybe_unused]] bool ConsumeName = Src.consume_front(Name);
177 assert(ConsumeName && "Expected name");
178 [[maybe_unused]] bool ConsumeDelim = Src.consume_front(SWaitAluDelim);
179 assert(ConsumeDelim && "Expected delimiter");
180 // Src: Num1_Name2_Num2
181 // ^
182 DelimIdx = Src.find(SWaitAluDelim);
183 // Src: Num1_Name2_Num2
184 // ^^^^
185 int64_t Num;
186 // Save the position of the number for accurate error reporting.
187 StringRef::iterator NumPos = Src.begin();
188 if (Src.consumeInteger(10, Num) || Num < 0)
189 return ErrorCallback(NumPos,
190 "expected non-negative integer counter number");
191 unsigned Max;
192 if (Name == VaVdstName) {
195 } else if (Name == VmVsrcName) {
198 } else if (Name == VaSdstName) {
201 } else if (Name == VaSsrcName) {
204 } else if (Name == HoldCntName) {
205 const AMDGPU::IsaVersion &Version = AMDGPU::getIsaVersion(STI.getCPU());
208 } else if (Name == VaVccName) {
211 } else if (Name == SaSdstName) {
214 } else {
215 return ErrorCallback(NamePos, "invalid counter name");
216 }
217 // Don't allow the values to reach their maximum value.
218 if (Num >= Max)
219 return ErrorCallback(NumPos, "counter value too large");
220 // Src: Name2_Num2
221 Src.consume_front(SWaitAluDelim);
222 }
223 return false;
224}
225
226bool AMDGPUMIRFormatter::parseSDelayAluImmMnemonic(
227 const unsigned int OpIdx, int64_t &Imm, llvm::StringRef &Src,
228 llvm::MIRFormatter::ErrorCallbackType &ErrorCallback) const
229{
230 assert(OpIdx == 0);
231
232 Imm = 0;
233 bool Expected = Src.consume_front(".id0_");
234 if (!Expected)
235 return ErrorCallback(Src.begin(), "Expected .id0_");
236
237 auto ExpectInt = [&](StringRef &Src, int64_t Offset) -> int64_t {
238 int64_t Dep;
239 if (!Src.consumeInteger(10, Dep))
240 return Dep + Offset;
241
242 return -1;
243 };
244
245 auto DecodeDelay = [&](StringRef &Src) -> int64_t {
246 if (Src.consume_front("NONE"))
247 return 0;
248 if (Src.consume_front("VALU_DEP_"))
249 return ExpectInt(Src, 0);
250 if (Src.consume_front("TRANS32_DEP_"))
251 return ExpectInt(Src, 4);
252 if (Src.consume_front("SALU_CYCLE_"))
253 return ExpectInt(Src, 8);
254
255 return -1;
256 };
257
258 int64_t Delay0 = DecodeDelay(Src);
259 int64_t Skip = 0;
260 int64_t Delay1 = 0;
261 if (Delay0 == -1)
262 return ErrorCallback(Src.begin(), "Could not decode delay0");
263
264
265 // Set the Imm so far, to that early return has the correct value.
266 Imm = Delay0;
267
268 // If that was the end of the string, the second instruction is "same" and
269 // "none"
270 if (Src.begin() == Src.end())
271 return false;
272
273 Expected = Src.consume_front("_skip_");
274 if (!Expected)
275 return ErrorCallback(Src.begin(), "Expected _skip_");
276
277
278 if (Src.consume_front("SAME")) {
279 Skip = 0;
280 } else if (Src.consume_front("NEXT")) {
281 Skip = 1;
282 } else if (Src.consume_front("SKIP_")) {
283 if (Src.consumeInteger(10, Skip)) {
284 return ErrorCallback(Src.begin(), "Expected integer Skip value");
285 }
286 Skip += 1;
287 } else {
288 ErrorCallback(Src.begin(), "Unexpected Skip Value");
289 }
290
291 Expected = Src.consume_front("_id1_");
292 if (!Expected)
293 return ErrorCallback(Src.begin(), "Expected _id1_");
294
295 Delay1 = DecodeDelay(Src);
296 if (Delay1 == -1)
297 return ErrorCallback(Src.begin(), "Could not decode delay1");
298
299 Imm = Imm | (Skip << 4) | (Delay1 << 7);
300 return false;
301}
302
305 const PseudoSourceValue *&PSV, ErrorCallbackType ErrorCallback) const {
307 const AMDGPUTargetMachine &TM =
308 static_cast<const AMDGPUTargetMachine &>(MF.getTarget());
309 if (Src == "GWSResource") {
310 PSV = MFI->getGWSPSV(TM);
311 return false;
312 }
313 llvm_unreachable("unknown MIR custom pseudo source value");
314}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
StringLiteral VmVsrcName
StringLiteral HoldCntName
StringLiteral AllOff
StringLiteral VaVccName
StringLiteral SWaitAluDelim
const char SWaitAluImmPrefix
StringLiteral VaSsrcName
StringLiteral VaSdstName
StringLiteral SaSdstName
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:864
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)
This is an optimization pass for GlobalISel generic memory operations.
Definition Types.h:26
@ Offset
Definition DWP.cpp:532
FunctionAddr VTableAddr uintptr_t uintptr_t Version
Definition InstrProf.h:302