1 | //===-- AMDGPUInstPrinter.cpp - AMDGPU MC Inst -> ASM ---------------------===// |
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 | // \file |
8 | //===----------------------------------------------------------------------===// |
9 | |
10 | #include "AMDGPUInstPrinter.h" |
11 | #include "MCTargetDesc/AMDGPUMCTargetDesc.h" |
12 | #include "SIDefines.h" |
13 | #include "Utils/AMDGPUAsmUtils.h" |
14 | #include "Utils/AMDGPUBaseInfo.h" |
15 | #include "llvm/MC/MCAsmInfo.h" |
16 | #include "llvm/MC/MCExpr.h" |
17 | #include "llvm/MC/MCInst.h" |
18 | #include "llvm/MC/MCInstrDesc.h" |
19 | #include "llvm/MC/MCInstrInfo.h" |
20 | #include "llvm/MC/MCRegisterInfo.h" |
21 | #include "llvm/MC/MCSubtargetInfo.h" |
22 | #include "llvm/TargetParser/TargetParser.h" |
23 | |
24 | using namespace llvm; |
25 | using namespace llvm::AMDGPU; |
26 | |
27 | void AMDGPUInstPrinter::printRegName(raw_ostream &OS, MCRegister Reg) { |
28 | // FIXME: The current implementation of |
29 | // AsmParser::parseRegisterOrRegisterNumber in MC implies we either emit this |
30 | // as an integer or we provide a name which represents a physical register. |
31 | // For CFI instructions we really want to emit a name for the DWARF register |
32 | // instead, because there may be multiple DWARF registers corresponding to a |
33 | // single physical register. One case where this problem manifests is with |
34 | // wave32/wave64 where using the physical register name is ambiguous: if we |
35 | // write e.g. `.cfi_undefined v0` we lose information about the wavefront |
36 | // size which we need to encode the register in the final DWARF. Ideally we |
37 | // would extend MC to support parsing DWARF register names so we could do |
38 | // something like `.cfi_undefined dwarf_wave32_v0`. For now we just live with |
39 | // non-pretty DWARF register names in assembly text. |
40 | OS << Reg.id(); |
41 | } |
42 | |
43 | void AMDGPUInstPrinter::printInst(const MCInst *MI, uint64_t Address, |
44 | StringRef Annot, const MCSubtargetInfo &STI, |
45 | raw_ostream &OS) { |
46 | printInstruction(MI, Address, STI, O&: OS); |
47 | printAnnotation(OS, Annot); |
48 | } |
49 | |
50 | void AMDGPUInstPrinter::printU16ImmOperand(const MCInst *MI, unsigned OpNo, |
51 | const MCSubtargetInfo &STI, |
52 | raw_ostream &O) { |
53 | const MCOperand &Op = MI->getOperand(i: OpNo); |
54 | if (Op.isExpr()) { |
55 | MAI.printExpr(O, *Op.getExpr()); |
56 | return; |
57 | } |
58 | |
59 | // It's possible to end up with a 32-bit literal used with a 16-bit operand |
60 | // with ignored high bits. Print as 32-bit anyway in that case. |
61 | int64_t Imm = Op.getImm(); |
62 | if (isInt<16>(x: Imm) || isUInt<16>(x: Imm)) |
63 | O << formatHex(Value: static_cast<uint64_t>(Imm & 0xffff)); |
64 | else |
65 | printU32ImmOperand(MI, OpNo, STI, O); |
66 | } |
67 | |
68 | void AMDGPUInstPrinter::printU16ImmDecOperand(const MCInst *MI, unsigned OpNo, |
69 | raw_ostream &O) { |
70 | O << formatDec(Value: MI->getOperand(i: OpNo).getImm() & 0xffff); |
71 | } |
72 | |
73 | void AMDGPUInstPrinter::printU32ImmOperand(const MCInst *MI, unsigned OpNo, |
74 | const MCSubtargetInfo &STI, |
75 | raw_ostream &O) { |
76 | O << formatHex(Value: MI->getOperand(i: OpNo).getImm() & 0xffffffff); |
77 | } |
78 | |
79 | void AMDGPUInstPrinter::printNamedBit(const MCInst *MI, unsigned OpNo, |
80 | raw_ostream &O, StringRef BitName) { |
81 | if (MI->getOperand(i: OpNo).getImm()) { |
82 | O << ' ' << BitName; |
83 | } |
84 | } |
85 | |
86 | void AMDGPUInstPrinter::printOffset(const MCInst *MI, unsigned OpNo, |
87 | const MCSubtargetInfo &STI, |
88 | raw_ostream &O) { |
89 | uint32_t Imm = MI->getOperand(i: OpNo).getImm(); |
90 | if (Imm != 0) { |
91 | O << " offset:" ; |
92 | |
93 | // GFX12 uses a 24-bit signed offset for VBUFFER. |
94 | const MCInstrDesc &Desc = MII.get(Opcode: MI->getOpcode()); |
95 | bool IsVBuffer = Desc.TSFlags & (SIInstrFlags::MUBUF | SIInstrFlags::MTBUF); |
96 | if (AMDGPU::isGFX12(STI) && IsVBuffer) |
97 | O << formatDec(Value: SignExtend32<24>(X: Imm)); |
98 | else |
99 | printU16ImmDecOperand(MI, OpNo, O); |
100 | } |
101 | } |
102 | |
103 | void AMDGPUInstPrinter::printFlatOffset(const MCInst *MI, unsigned OpNo, |
104 | const MCSubtargetInfo &STI, |
105 | raw_ostream &O) { |
106 | uint32_t Imm = MI->getOperand(i: OpNo).getImm(); |
107 | if (Imm != 0) { |
108 | O << " offset:" ; |
109 | |
110 | const MCInstrDesc &Desc = MII.get(Opcode: MI->getOpcode()); |
111 | bool AllowNegative = (Desc.TSFlags & (SIInstrFlags::FlatGlobal | |
112 | SIInstrFlags::FlatScratch)) || |
113 | AMDGPU::isGFX12(STI); |
114 | |
115 | if (AllowNegative) // Signed offset |
116 | O << formatDec(Value: SignExtend32(X: Imm, B: AMDGPU::getNumFlatOffsetBits(ST: STI))); |
117 | else // Unsigned offset |
118 | printU16ImmDecOperand(MI, OpNo, O); |
119 | } |
120 | } |
121 | |
122 | void AMDGPUInstPrinter::printSMRDOffset8(const MCInst *MI, unsigned OpNo, |
123 | const MCSubtargetInfo &STI, |
124 | raw_ostream &O) { |
125 | printU32ImmOperand(MI, OpNo, STI, O); |
126 | } |
127 | |
128 | void AMDGPUInstPrinter::printSMEMOffset(const MCInst *MI, unsigned OpNo, |
129 | const MCSubtargetInfo &STI, |
130 | raw_ostream &O) { |
131 | O << formatHex(Value: MI->getOperand(i: OpNo).getImm()); |
132 | } |
133 | |
134 | void AMDGPUInstPrinter::printSMRDLiteralOffset(const MCInst *MI, unsigned OpNo, |
135 | const MCSubtargetInfo &STI, |
136 | raw_ostream &O) { |
137 | printU32ImmOperand(MI, OpNo, STI, O); |
138 | } |
139 | |
140 | void AMDGPUInstPrinter::printCPol(const MCInst *MI, unsigned OpNo, |
141 | const MCSubtargetInfo &STI, raw_ostream &O) { |
142 | auto Imm = MI->getOperand(i: OpNo).getImm(); |
143 | |
144 | if (AMDGPU::isGFX12Plus(STI)) { |
145 | const int64_t TH = Imm & CPol::TH; |
146 | const int64_t Scope = Imm & CPol::SCOPE; |
147 | |
148 | printTH(MI, TH, Scope, O); |
149 | printScope(Scope, O); |
150 | |
151 | return; |
152 | } |
153 | |
154 | if (Imm & CPol::GLC) |
155 | O << ((AMDGPU::isGFX940(STI) && |
156 | !(MII.get(Opcode: MI->getOpcode()).TSFlags & SIInstrFlags::SMRD)) ? " sc0" |
157 | : " glc" ); |
158 | if (Imm & CPol::SLC) |
159 | O << (AMDGPU::isGFX940(STI) ? " nt" : " slc" ); |
160 | if ((Imm & CPol::DLC) && AMDGPU::isGFX10Plus(STI)) |
161 | O << " dlc" ; |
162 | if ((Imm & CPol::SCC) && AMDGPU::isGFX90A(STI)) |
163 | O << (AMDGPU::isGFX940(STI) ? " sc1" : " scc" ); |
164 | if (Imm & ~CPol::ALL_pregfx12) |
165 | O << " /* unexpected cache policy bit */" ; |
166 | } |
167 | |
168 | void AMDGPUInstPrinter::printTH(const MCInst *MI, int64_t TH, int64_t Scope, |
169 | raw_ostream &O) { |
170 | // For th = 0 do not print this field |
171 | if (TH == 0) |
172 | return; |
173 | |
174 | const unsigned Opcode = MI->getOpcode(); |
175 | const MCInstrDesc &TID = MII.get(Opcode); |
176 | unsigned THType = AMDGPU::getTemporalHintType(TID); |
177 | bool IsStore = (THType == AMDGPU::CPol::TH_TYPE_STORE); |
178 | |
179 | O << " th:" ; |
180 | |
181 | if (THType == AMDGPU::CPol::TH_TYPE_ATOMIC) { |
182 | O << "TH_ATOMIC_" ; |
183 | if (TH & AMDGPU::CPol::TH_ATOMIC_CASCADE) { |
184 | if (Scope >= AMDGPU::CPol::SCOPE_DEV) |
185 | O << "CASCADE" << (TH & AMDGPU::CPol::TH_ATOMIC_NT ? "_NT" : "_RT" ); |
186 | else |
187 | O << formatHex(Value: TH); |
188 | } else if (TH & AMDGPU::CPol::TH_ATOMIC_NT) |
189 | O << "NT" << (TH & AMDGPU::CPol::TH_ATOMIC_RETURN ? "_RETURN" : "" ); |
190 | else if (TH & AMDGPU::CPol::TH_ATOMIC_RETURN) |
191 | O << "RETURN" ; |
192 | else |
193 | O << formatHex(Value: TH); |
194 | } else { |
195 | if (!IsStore && TH == AMDGPU::CPol::TH_RESERVED) |
196 | O << formatHex(Value: TH); |
197 | else { |
198 | O << (IsStore ? "TH_STORE_" : "TH_LOAD_" ); |
199 | switch (TH) { |
200 | case AMDGPU::CPol::TH_NT: |
201 | O << "NT" ; |
202 | break; |
203 | case AMDGPU::CPol::TH_HT: |
204 | O << "HT" ; |
205 | break; |
206 | case AMDGPU::CPol::TH_BYPASS: // or LU or WB |
207 | O << (Scope == AMDGPU::CPol::SCOPE_SYS ? "BYPASS" |
208 | : (IsStore ? "WB" : "LU" )); |
209 | break; |
210 | case AMDGPU::CPol::TH_NT_RT: |
211 | O << "NT_RT" ; |
212 | break; |
213 | case AMDGPU::CPol::TH_RT_NT: |
214 | O << "RT_NT" ; |
215 | break; |
216 | case AMDGPU::CPol::TH_NT_HT: |
217 | O << "NT_HT" ; |
218 | break; |
219 | case AMDGPU::CPol::TH_NT_WB: |
220 | O << "NT_WB" ; |
221 | break; |
222 | default: |
223 | llvm_unreachable("unexpected th value" ); |
224 | } |
225 | } |
226 | } |
227 | } |
228 | |
229 | void AMDGPUInstPrinter::printScope(int64_t Scope, raw_ostream &O) { |
230 | if (Scope == CPol::SCOPE_CU) |
231 | return; |
232 | |
233 | O << " scope:" ; |
234 | |
235 | if (Scope == CPol::SCOPE_SE) |
236 | O << "SCOPE_SE" ; |
237 | else if (Scope == CPol::SCOPE_DEV) |
238 | O << "SCOPE_DEV" ; |
239 | else if (Scope == CPol::SCOPE_SYS) |
240 | O << "SCOPE_SYS" ; |
241 | else |
242 | llvm_unreachable("unexpected scope policy value" ); |
243 | } |
244 | |
245 | void AMDGPUInstPrinter::printDim(const MCInst *MI, unsigned OpNo, |
246 | const MCSubtargetInfo &STI, raw_ostream &O) { |
247 | unsigned Dim = MI->getOperand(i: OpNo).getImm(); |
248 | O << " dim:SQ_RSRC_IMG_" ; |
249 | |
250 | const AMDGPU::MIMGDimInfo *DimInfo = AMDGPU::getMIMGDimInfoByEncoding(DimEnc: Dim); |
251 | if (DimInfo) |
252 | O << DimInfo->AsmSuffix; |
253 | else |
254 | O << Dim; |
255 | } |
256 | |
257 | void AMDGPUInstPrinter::printR128A16(const MCInst *MI, unsigned OpNo, |
258 | const MCSubtargetInfo &STI, raw_ostream &O) { |
259 | if (STI.hasFeature(Feature: AMDGPU::FeatureR128A16)) |
260 | printNamedBit(MI, OpNo, O, BitName: "a16" ); |
261 | else |
262 | printNamedBit(MI, OpNo, O, BitName: "r128" ); |
263 | } |
264 | |
265 | void AMDGPUInstPrinter::printFORMAT(const MCInst *MI, unsigned OpNo, |
266 | const MCSubtargetInfo &STI, |
267 | raw_ostream &O) { |
268 | } |
269 | |
270 | void AMDGPUInstPrinter::printSymbolicFormat(const MCInst *MI, |
271 | const MCSubtargetInfo &STI, |
272 | raw_ostream &O) { |
273 | using namespace llvm::AMDGPU::MTBUFFormat; |
274 | |
275 | int OpNo = |
276 | AMDGPU::getNamedOperandIdx(Opcode: MI->getOpcode(), Name: AMDGPU::OpName::format); |
277 | assert(OpNo != -1); |
278 | |
279 | unsigned Val = MI->getOperand(i: OpNo).getImm(); |
280 | if (AMDGPU::isGFX10Plus(STI)) { |
281 | if (Val == UFMT_DEFAULT) |
282 | return; |
283 | if (isValidUnifiedFormat(Val, STI)) { |
284 | O << " format:[" << getUnifiedFormatName(Id: Val, STI) << ']'; |
285 | } else { |
286 | O << " format:" << Val; |
287 | } |
288 | } else { |
289 | if (Val == DFMT_NFMT_DEFAULT) |
290 | return; |
291 | if (isValidDfmtNfmt(Val, STI)) { |
292 | unsigned Dfmt; |
293 | unsigned Nfmt; |
294 | decodeDfmtNfmt(Format: Val, Dfmt, Nfmt); |
295 | O << " format:[" ; |
296 | if (Dfmt != DFMT_DEFAULT) { |
297 | O << getDfmtName(Id: Dfmt); |
298 | if (Nfmt != NFMT_DEFAULT) { |
299 | O << ','; |
300 | } |
301 | } |
302 | if (Nfmt != NFMT_DEFAULT) { |
303 | O << getNfmtName(Id: Nfmt, STI); |
304 | } |
305 | O << ']'; |
306 | } else { |
307 | O << " format:" << Val; |
308 | } |
309 | } |
310 | } |
311 | |
312 | void AMDGPUInstPrinter::printRegOperand(MCRegister Reg, raw_ostream &O, |
313 | const MCRegisterInfo &MRI) { |
314 | #if !defined(NDEBUG) |
315 | switch (Reg.id()) { |
316 | case AMDGPU::FP_REG: |
317 | case AMDGPU::SP_REG: |
318 | case AMDGPU::PRIVATE_RSRC_REG: |
319 | llvm_unreachable("pseudo-register should not ever be emitted" ); |
320 | default: |
321 | break; |
322 | } |
323 | #endif |
324 | |
325 | O << getRegisterName(Reg); |
326 | } |
327 | |
328 | void AMDGPUInstPrinter::printVOPDst(const MCInst *MI, unsigned OpNo, |
329 | const MCSubtargetInfo &STI, raw_ostream &O) { |
330 | auto Opcode = MI->getOpcode(); |
331 | auto Flags = MII.get(Opcode).TSFlags; |
332 | if (OpNo == 0) { |
333 | if (Flags & SIInstrFlags::VOP3 && Flags & SIInstrFlags::DPP) |
334 | O << "_e64_dpp" ; |
335 | else if (Flags & SIInstrFlags::VOP3) { |
336 | if (!getVOP3IsSingle(Opc: Opcode)) |
337 | O << "_e64" ; |
338 | } else if (Flags & SIInstrFlags::DPP) |
339 | O << "_dpp" ; |
340 | else if (Flags & SIInstrFlags::SDWA) |
341 | O << "_sdwa" ; |
342 | else if (((Flags & SIInstrFlags::VOP1) && !getVOP1IsSingle(Opc: Opcode)) || |
343 | ((Flags & SIInstrFlags::VOP2) && !getVOP2IsSingle(Opc: Opcode))) |
344 | O << "_e32" ; |
345 | O << " " ; |
346 | } |
347 | |
348 | printRegularOperand(MI, OpNo, STI, O); |
349 | |
350 | // Print default vcc/vcc_lo operand. |
351 | switch (Opcode) { |
352 | default: break; |
353 | |
354 | case AMDGPU::V_ADD_CO_CI_U32_e32_gfx10: |
355 | case AMDGPU::V_SUB_CO_CI_U32_e32_gfx10: |
356 | case AMDGPU::V_SUBREV_CO_CI_U32_e32_gfx10: |
357 | case AMDGPU::V_ADD_CO_CI_U32_sdwa_gfx10: |
358 | case AMDGPU::V_SUB_CO_CI_U32_sdwa_gfx10: |
359 | case AMDGPU::V_SUBREV_CO_CI_U32_sdwa_gfx10: |
360 | case AMDGPU::V_ADD_CO_CI_U32_dpp_gfx10: |
361 | case AMDGPU::V_SUB_CO_CI_U32_dpp_gfx10: |
362 | case AMDGPU::V_SUBREV_CO_CI_U32_dpp_gfx10: |
363 | case AMDGPU::V_ADD_CO_CI_U32_dpp8_gfx10: |
364 | case AMDGPU::V_SUB_CO_CI_U32_dpp8_gfx10: |
365 | case AMDGPU::V_SUBREV_CO_CI_U32_dpp8_gfx10: |
366 | case AMDGPU::V_ADD_CO_CI_U32_e32_gfx11: |
367 | case AMDGPU::V_SUB_CO_CI_U32_e32_gfx11: |
368 | case AMDGPU::V_SUBREV_CO_CI_U32_e32_gfx11: |
369 | case AMDGPU::V_ADD_CO_CI_U32_dpp_gfx11: |
370 | case AMDGPU::V_SUB_CO_CI_U32_dpp_gfx11: |
371 | case AMDGPU::V_SUBREV_CO_CI_U32_dpp_gfx11: |
372 | case AMDGPU::V_ADD_CO_CI_U32_dpp8_gfx11: |
373 | case AMDGPU::V_SUB_CO_CI_U32_dpp8_gfx11: |
374 | case AMDGPU::V_SUBREV_CO_CI_U32_dpp8_gfx11: |
375 | case AMDGPU::V_ADD_CO_CI_U32_e32_gfx12: |
376 | case AMDGPU::V_SUB_CO_CI_U32_e32_gfx12: |
377 | case AMDGPU::V_SUBREV_CO_CI_U32_e32_gfx12: |
378 | case AMDGPU::V_ADD_CO_CI_U32_dpp_gfx12: |
379 | case AMDGPU::V_SUB_CO_CI_U32_dpp_gfx12: |
380 | case AMDGPU::V_SUBREV_CO_CI_U32_dpp_gfx12: |
381 | case AMDGPU::V_ADD_CO_CI_U32_dpp8_gfx12: |
382 | case AMDGPU::V_SUB_CO_CI_U32_dpp8_gfx12: |
383 | case AMDGPU::V_SUBREV_CO_CI_U32_dpp8_gfx12: |
384 | printDefaultVccOperand(FirstOperand: false, STI, O); |
385 | break; |
386 | } |
387 | } |
388 | |
389 | void AMDGPUInstPrinter::printVINTRPDst(const MCInst *MI, unsigned OpNo, |
390 | const MCSubtargetInfo &STI, raw_ostream &O) { |
391 | if (AMDGPU::isSI(STI) || AMDGPU::isCI(STI)) |
392 | O << " " ; |
393 | else |
394 | O << "_e32 " ; |
395 | |
396 | printRegularOperand(MI, OpNo, STI, O); |
397 | } |
398 | |
399 | void AMDGPUInstPrinter::printImmediateInt16(uint32_t Imm, |
400 | const MCSubtargetInfo &STI, |
401 | raw_ostream &O) { |
402 | int32_t SImm = static_cast<int32_t>(Imm); |
403 | if (isInlinableIntLiteral(Literal: SImm)) { |
404 | O << SImm; |
405 | return; |
406 | } |
407 | |
408 | if (printImmediateFloat32(Imm, STI, O)) |
409 | return; |
410 | |
411 | O << formatHex(Value: static_cast<uint64_t>(Imm & 0xffff)); |
412 | } |
413 | |
414 | static bool printImmediateFP16(uint32_t Imm, const MCSubtargetInfo &STI, |
415 | raw_ostream &O) { |
416 | if (Imm == 0x3C00) |
417 | O << "1.0" ; |
418 | else if (Imm == 0xBC00) |
419 | O << "-1.0" ; |
420 | else if (Imm == 0x3800) |
421 | O << "0.5" ; |
422 | else if (Imm == 0xB800) |
423 | O << "-0.5" ; |
424 | else if (Imm == 0x4000) |
425 | O << "2.0" ; |
426 | else if (Imm == 0xC000) |
427 | O << "-2.0" ; |
428 | else if (Imm == 0x4400) |
429 | O << "4.0" ; |
430 | else if (Imm == 0xC400) |
431 | O << "-4.0" ; |
432 | else if (Imm == 0x3118 && STI.hasFeature(Feature: AMDGPU::FeatureInv2PiInlineImm)) |
433 | O << "0.15915494" ; |
434 | else |
435 | return false; |
436 | |
437 | return true; |
438 | } |
439 | |
440 | static bool printImmediateBFloat16(uint32_t Imm, const MCSubtargetInfo &STI, |
441 | raw_ostream &O) { |
442 | if (Imm == 0x3F80) |
443 | O << "1.0" ; |
444 | else if (Imm == 0xBF80) |
445 | O << "-1.0" ; |
446 | else if (Imm == 0x3F00) |
447 | O << "0.5" ; |
448 | else if (Imm == 0xBF00) |
449 | O << "-0.5" ; |
450 | else if (Imm == 0x4000) |
451 | O << "2.0" ; |
452 | else if (Imm == 0xC000) |
453 | O << "-2.0" ; |
454 | else if (Imm == 0x4080) |
455 | O << "4.0" ; |
456 | else if (Imm == 0xC080) |
457 | O << "-4.0" ; |
458 | else if (Imm == 0x3E22 && STI.hasFeature(Feature: AMDGPU::FeatureInv2PiInlineImm)) |
459 | O << "0.15915494" ; |
460 | else |
461 | return false; |
462 | |
463 | return true; |
464 | } |
465 | |
466 | void AMDGPUInstPrinter::printImmediateBF16(uint32_t Imm, |
467 | const MCSubtargetInfo &STI, |
468 | raw_ostream &O) { |
469 | int16_t SImm = static_cast<int16_t>(Imm); |
470 | if (isInlinableIntLiteral(Literal: SImm)) { |
471 | O << SImm; |
472 | return; |
473 | } |
474 | |
475 | if (printImmediateBFloat16(Imm: static_cast<uint16_t>(Imm), STI, O)) |
476 | return; |
477 | |
478 | O << formatHex(Value: static_cast<uint64_t>(Imm)); |
479 | } |
480 | |
481 | void AMDGPUInstPrinter::printImmediateF16(uint32_t Imm, |
482 | const MCSubtargetInfo &STI, |
483 | raw_ostream &O) { |
484 | int16_t SImm = static_cast<int16_t>(Imm); |
485 | if (isInlinableIntLiteral(Literal: SImm)) { |
486 | O << SImm; |
487 | return; |
488 | } |
489 | |
490 | uint16_t HImm = static_cast<uint16_t>(Imm); |
491 | if (printImmediateFP16(Imm: HImm, STI, O)) |
492 | return; |
493 | |
494 | uint64_t Imm16 = static_cast<uint16_t>(Imm); |
495 | O << formatHex(Value: Imm16); |
496 | } |
497 | |
498 | void AMDGPUInstPrinter::printImmediateV216(uint32_t Imm, uint8_t OpType, |
499 | const MCSubtargetInfo &STI, |
500 | raw_ostream &O) { |
501 | int32_t SImm = static_cast<int32_t>(Imm); |
502 | if (isInlinableIntLiteral(Literal: SImm)) { |
503 | O << SImm; |
504 | return; |
505 | } |
506 | |
507 | switch (OpType) { |
508 | case AMDGPU::OPERAND_REG_IMM_V2INT16: |
509 | case AMDGPU::OPERAND_REG_INLINE_C_V2INT16: |
510 | if (printImmediateFloat32(Imm, STI, O)) |
511 | return; |
512 | break; |
513 | case AMDGPU::OPERAND_REG_IMM_V2FP16: |
514 | case AMDGPU::OPERAND_REG_INLINE_C_V2FP16: |
515 | if (isUInt<16>(x: Imm) && |
516 | printImmediateFP16(Imm: static_cast<uint16_t>(Imm), STI, O)) |
517 | return; |
518 | break; |
519 | case AMDGPU::OPERAND_REG_IMM_V2BF16: |
520 | case AMDGPU::OPERAND_REG_INLINE_C_V2BF16: |
521 | if (isUInt<16>(x: Imm) && |
522 | printImmediateBFloat16(Imm: static_cast<uint16_t>(Imm), STI, O)) |
523 | return; |
524 | break; |
525 | default: |
526 | llvm_unreachable("bad operand type" ); |
527 | } |
528 | |
529 | O << formatHex(Value: static_cast<uint64_t>(Imm)); |
530 | } |
531 | |
532 | bool AMDGPUInstPrinter::printImmediateFloat32(uint32_t Imm, |
533 | const MCSubtargetInfo &STI, |
534 | raw_ostream &O) { |
535 | if (Imm == llvm::bit_cast<uint32_t>(from: 0.0f)) |
536 | O << "0.0" ; |
537 | else if (Imm == llvm::bit_cast<uint32_t>(from: 1.0f)) |
538 | O << "1.0" ; |
539 | else if (Imm == llvm::bit_cast<uint32_t>(from: -1.0f)) |
540 | O << "-1.0" ; |
541 | else if (Imm == llvm::bit_cast<uint32_t>(from: 0.5f)) |
542 | O << "0.5" ; |
543 | else if (Imm == llvm::bit_cast<uint32_t>(from: -0.5f)) |
544 | O << "-0.5" ; |
545 | else if (Imm == llvm::bit_cast<uint32_t>(from: 2.0f)) |
546 | O << "2.0" ; |
547 | else if (Imm == llvm::bit_cast<uint32_t>(from: -2.0f)) |
548 | O << "-2.0" ; |
549 | else if (Imm == llvm::bit_cast<uint32_t>(from: 4.0f)) |
550 | O << "4.0" ; |
551 | else if (Imm == llvm::bit_cast<uint32_t>(from: -4.0f)) |
552 | O << "-4.0" ; |
553 | else if (Imm == 0x3e22f983 && |
554 | STI.hasFeature(Feature: AMDGPU::FeatureInv2PiInlineImm)) |
555 | O << "0.15915494" ; |
556 | else |
557 | return false; |
558 | |
559 | return true; |
560 | } |
561 | |
562 | void AMDGPUInstPrinter::printImmediate32(uint32_t Imm, |
563 | const MCSubtargetInfo &STI, |
564 | raw_ostream &O) { |
565 | int32_t SImm = static_cast<int32_t>(Imm); |
566 | if (isInlinableIntLiteral(Literal: SImm)) { |
567 | O << SImm; |
568 | return; |
569 | } |
570 | |
571 | if (printImmediateFloat32(Imm, STI, O)) |
572 | return; |
573 | |
574 | O << formatHex(Value: static_cast<uint64_t>(Imm)); |
575 | } |
576 | |
577 | void AMDGPUInstPrinter::printImmediate64(uint64_t Imm, |
578 | const MCSubtargetInfo &STI, |
579 | raw_ostream &O, bool IsFP) { |
580 | int64_t SImm = static_cast<int64_t>(Imm); |
581 | if (SImm >= -16 && SImm <= 64) { |
582 | O << SImm; |
583 | return; |
584 | } |
585 | |
586 | if (Imm == llvm::bit_cast<uint64_t>(from: 0.0)) |
587 | O << "0.0" ; |
588 | else if (Imm == llvm::bit_cast<uint64_t>(from: 1.0)) |
589 | O << "1.0" ; |
590 | else if (Imm == llvm::bit_cast<uint64_t>(from: -1.0)) |
591 | O << "-1.0" ; |
592 | else if (Imm == llvm::bit_cast<uint64_t>(from: 0.5)) |
593 | O << "0.5" ; |
594 | else if (Imm == llvm::bit_cast<uint64_t>(from: -0.5)) |
595 | O << "-0.5" ; |
596 | else if (Imm == llvm::bit_cast<uint64_t>(from: 2.0)) |
597 | O << "2.0" ; |
598 | else if (Imm == llvm::bit_cast<uint64_t>(from: -2.0)) |
599 | O << "-2.0" ; |
600 | else if (Imm == llvm::bit_cast<uint64_t>(from: 4.0)) |
601 | O << "4.0" ; |
602 | else if (Imm == llvm::bit_cast<uint64_t>(from: -4.0)) |
603 | O << "-4.0" ; |
604 | else if (Imm == 0x3fc45f306dc9c882 && |
605 | STI.hasFeature(Feature: AMDGPU::FeatureInv2PiInlineImm)) |
606 | O << "0.15915494309189532" ; |
607 | else if (IsFP) { |
608 | assert(AMDGPU::isValid32BitLiteral(Imm, true)); |
609 | O << formatHex(Value: static_cast<uint64_t>(Hi_32(Value: Imm))); |
610 | } else { |
611 | assert(isUInt<32>(Imm) || isInt<32>(Imm)); |
612 | |
613 | // In rare situations, we will have a 32-bit literal in a 64-bit |
614 | // operand. This is technically allowed for the encoding of s_mov_b64. |
615 | O << formatHex(Value: static_cast<uint64_t>(Imm)); |
616 | } |
617 | } |
618 | |
619 | void AMDGPUInstPrinter::printBLGP(const MCInst *MI, unsigned OpNo, |
620 | const MCSubtargetInfo &STI, |
621 | raw_ostream &O) { |
622 | unsigned Imm = MI->getOperand(i: OpNo).getImm(); |
623 | if (!Imm) |
624 | return; |
625 | |
626 | if (AMDGPU::isGFX940(STI)) { |
627 | switch (MI->getOpcode()) { |
628 | case AMDGPU::V_MFMA_F64_16X16X4F64_gfx940_acd: |
629 | case AMDGPU::V_MFMA_F64_16X16X4F64_gfx940_vcd: |
630 | case AMDGPU::V_MFMA_F64_4X4X4F64_gfx940_acd: |
631 | case AMDGPU::V_MFMA_F64_4X4X4F64_gfx940_vcd: |
632 | O << " neg:[" << (Imm & 1) << ',' << ((Imm >> 1) & 1) << ',' |
633 | << ((Imm >> 2) & 1) << ']'; |
634 | return; |
635 | } |
636 | } |
637 | |
638 | O << " blgp:" << Imm; |
639 | } |
640 | |
641 | void AMDGPUInstPrinter::printDefaultVccOperand(bool FirstOperand, |
642 | const MCSubtargetInfo &STI, |
643 | raw_ostream &O) { |
644 | if (!FirstOperand) |
645 | O << ", " ; |
646 | printRegOperand(Reg: STI.hasFeature(Feature: AMDGPU::FeatureWavefrontSize32) |
647 | ? AMDGPU::VCC_LO |
648 | : AMDGPU::VCC, |
649 | O, MRI); |
650 | if (FirstOperand) |
651 | O << ", " ; |
652 | } |
653 | |
654 | bool AMDGPUInstPrinter::needsImpliedVcc(const MCInstrDesc &Desc, |
655 | unsigned OpNo) const { |
656 | return OpNo == 0 && (Desc.TSFlags & SIInstrFlags::DPP) && |
657 | (Desc.TSFlags & SIInstrFlags::VOPC) && |
658 | !isVOPCAsmOnly(Opc: Desc.getOpcode()) && |
659 | (Desc.hasImplicitDefOfPhysReg(Reg: AMDGPU::VCC) || |
660 | Desc.hasImplicitDefOfPhysReg(Reg: AMDGPU::VCC_LO)); |
661 | } |
662 | |
663 | // Print default vcc/vcc_lo operand of VOPC. |
664 | void AMDGPUInstPrinter::printOperand(const MCInst *MI, unsigned OpNo, |
665 | const MCSubtargetInfo &STI, |
666 | raw_ostream &O) { |
667 | unsigned Opc = MI->getOpcode(); |
668 | const MCInstrDesc &Desc = MII.get(Opcode: Opc); |
669 | int ModIdx = AMDGPU::getNamedOperandIdx(Opcode: Opc, Name: AMDGPU::OpName::src0_modifiers); |
670 | // 0, 1 and 2 are the first printed operands in different cases |
671 | // If there are printed modifiers, printOperandAndFPInputMods or |
672 | // printOperandAndIntInputMods will be called instead |
673 | if ((OpNo == 0 || |
674 | (OpNo == 1 && (Desc.TSFlags & SIInstrFlags::DPP) && ModIdx != -1)) && |
675 | (Desc.TSFlags & SIInstrFlags::VOPC) && !isVOPCAsmOnly(Opc: Desc.getOpcode()) && |
676 | (Desc.hasImplicitDefOfPhysReg(Reg: AMDGPU::VCC) || |
677 | Desc.hasImplicitDefOfPhysReg(Reg: AMDGPU::VCC_LO))) |
678 | printDefaultVccOperand(FirstOperand: true, STI, O); |
679 | |
680 | printRegularOperand(MI, OpNo, STI, O); |
681 | } |
682 | |
683 | // Print operands after vcc or modifier handling. |
684 | void AMDGPUInstPrinter::printRegularOperand(const MCInst *MI, unsigned OpNo, |
685 | const MCSubtargetInfo &STI, |
686 | raw_ostream &O) { |
687 | const MCInstrDesc &Desc = MII.get(Opcode: MI->getOpcode()); |
688 | |
689 | if (OpNo >= MI->getNumOperands()) { |
690 | O << "/*Missing OP" << OpNo << "*/" ; |
691 | return; |
692 | } |
693 | |
694 | const MCOperand &Op = MI->getOperand(i: OpNo); |
695 | if (Op.isReg()) { |
696 | printRegOperand(Reg: Op.getReg(), O, MRI); |
697 | |
698 | // Check if operand register class contains register used. |
699 | // Intention: print disassembler message when invalid code is decoded, |
700 | // for example sgpr register used in VReg or VISrc(VReg or imm) operand. |
701 | int RCID = Desc.operands()[OpNo].RegClass; |
702 | if (RCID != -1) { |
703 | const MCRegisterClass RC = MRI.getRegClass(i: RCID); |
704 | auto Reg = mc2PseudoReg(Reg: Op.getReg()); |
705 | if (!RC.contains(Reg) && !isInlineValue(Reg)) { |
706 | O << "/*Invalid register, operand has \'" << MRI.getRegClassName(Class: &RC) |
707 | << "\' register class*/" ; |
708 | } |
709 | } |
710 | } else if (Op.isImm()) { |
711 | const uint8_t OpTy = Desc.operands()[OpNo].OperandType; |
712 | switch (OpTy) { |
713 | case AMDGPU::OPERAND_REG_IMM_INT32: |
714 | case AMDGPU::OPERAND_REG_IMM_FP32: |
715 | case AMDGPU::OPERAND_REG_INLINE_C_INT32: |
716 | case AMDGPU::OPERAND_REG_INLINE_C_FP32: |
717 | case AMDGPU::OPERAND_REG_INLINE_AC_INT32: |
718 | case AMDGPU::OPERAND_REG_INLINE_AC_FP32: |
719 | case AMDGPU::OPERAND_REG_IMM_V2INT32: |
720 | case AMDGPU::OPERAND_REG_IMM_V2FP32: |
721 | case MCOI::OPERAND_IMMEDIATE: |
722 | case AMDGPU::OPERAND_INLINE_SPLIT_BARRIER_INT32: |
723 | printImmediate32(Imm: Op.getImm(), STI, O); |
724 | break; |
725 | case AMDGPU::OPERAND_REG_IMM_INT64: |
726 | case AMDGPU::OPERAND_REG_INLINE_C_INT64: |
727 | printImmediate64(Imm: Op.getImm(), STI, O, IsFP: false); |
728 | break; |
729 | case AMDGPU::OPERAND_REG_IMM_FP64: |
730 | case AMDGPU::OPERAND_REG_INLINE_C_FP64: |
731 | case AMDGPU::OPERAND_REG_INLINE_AC_FP64: |
732 | printImmediate64(Imm: Op.getImm(), STI, O, IsFP: true); |
733 | break; |
734 | case AMDGPU::OPERAND_REG_INLINE_C_INT16: |
735 | case AMDGPU::OPERAND_REG_IMM_INT16: |
736 | printImmediateInt16(Imm: Op.getImm(), STI, O); |
737 | break; |
738 | case AMDGPU::OPERAND_REG_INLINE_C_FP16: |
739 | case AMDGPU::OPERAND_REG_IMM_FP16: |
740 | printImmediateF16(Imm: Op.getImm(), STI, O); |
741 | break; |
742 | case AMDGPU::OPERAND_REG_INLINE_C_BF16: |
743 | case AMDGPU::OPERAND_REG_IMM_BF16: |
744 | printImmediateBF16(Imm: Op.getImm(), STI, O); |
745 | break; |
746 | case AMDGPU::OPERAND_REG_IMM_V2INT16: |
747 | case AMDGPU::OPERAND_REG_IMM_V2BF16: |
748 | case AMDGPU::OPERAND_REG_IMM_V2FP16: |
749 | case AMDGPU::OPERAND_REG_INLINE_C_V2INT16: |
750 | case AMDGPU::OPERAND_REG_INLINE_C_V2BF16: |
751 | case AMDGPU::OPERAND_REG_INLINE_C_V2FP16: |
752 | printImmediateV216(Imm: Op.getImm(), OpType: OpTy, STI, O); |
753 | break; |
754 | case MCOI::OPERAND_UNKNOWN: |
755 | case MCOI::OPERAND_PCREL: |
756 | O << formatDec(Value: Op.getImm()); |
757 | break; |
758 | case MCOI::OPERAND_REGISTER: |
759 | // Disassembler does not fail when operand should not allow immediate |
760 | // operands but decodes them into 32bit immediate operand. |
761 | printImmediate32(Imm: Op.getImm(), STI, O); |
762 | O << "/*Invalid immediate*/" ; |
763 | break; |
764 | default: |
765 | // We hit this for the immediate instruction bits that don't yet have a |
766 | // custom printer. |
767 | llvm_unreachable("unexpected immediate operand type" ); |
768 | } |
769 | } else if (Op.isDFPImm()) { |
770 | double Value = bit_cast<double>(from: Op.getDFPImm()); |
771 | // We special case 0.0 because otherwise it will be printed as an integer. |
772 | if (Value == 0.0) |
773 | O << "0.0" ; |
774 | else { |
775 | const MCInstrDesc &Desc = MII.get(Opcode: MI->getOpcode()); |
776 | int RCID = Desc.operands()[OpNo].RegClass; |
777 | unsigned RCBits = AMDGPU::getRegBitWidth(RC: MRI.getRegClass(i: RCID)); |
778 | if (RCBits == 32) |
779 | printImmediate32(Imm: llvm::bit_cast<uint32_t>(from: (float)Value), STI, O); |
780 | else if (RCBits == 64) |
781 | printImmediate64(Imm: llvm::bit_cast<uint64_t>(from: Value), STI, O, IsFP: true); |
782 | else |
783 | llvm_unreachable("Invalid register class size" ); |
784 | } |
785 | } else if (Op.isExpr()) { |
786 | const MCExpr *Exp = Op.getExpr(); |
787 | MAI.printExpr(O, *Exp); |
788 | } else { |
789 | O << "/*INV_OP*/" ; |
790 | } |
791 | |
792 | // Print default vcc/vcc_lo operand of v_cndmask_b32_e32. |
793 | switch (MI->getOpcode()) { |
794 | default: break; |
795 | |
796 | case AMDGPU::V_CNDMASK_B32_e32_gfx10: |
797 | case AMDGPU::V_ADD_CO_CI_U32_e32_gfx10: |
798 | case AMDGPU::V_SUB_CO_CI_U32_e32_gfx10: |
799 | case AMDGPU::V_SUBREV_CO_CI_U32_e32_gfx10: |
800 | case AMDGPU::V_ADD_CO_CI_U32_dpp_gfx10: |
801 | case AMDGPU::V_SUB_CO_CI_U32_dpp_gfx10: |
802 | case AMDGPU::V_SUBREV_CO_CI_U32_dpp_gfx10: |
803 | case AMDGPU::V_CNDMASK_B32_dpp8_gfx10: |
804 | case AMDGPU::V_ADD_CO_CI_U32_dpp8_gfx10: |
805 | case AMDGPU::V_SUB_CO_CI_U32_dpp8_gfx10: |
806 | case AMDGPU::V_SUBREV_CO_CI_U32_dpp8_gfx10: |
807 | case AMDGPU::V_CNDMASK_B32_e32_gfx11: |
808 | case AMDGPU::V_ADD_CO_CI_U32_e32_gfx11: |
809 | case AMDGPU::V_SUB_CO_CI_U32_e32_gfx11: |
810 | case AMDGPU::V_SUBREV_CO_CI_U32_e32_gfx11: |
811 | case AMDGPU::V_ADD_CO_CI_U32_dpp_gfx11: |
812 | case AMDGPU::V_SUB_CO_CI_U32_dpp_gfx11: |
813 | case AMDGPU::V_SUBREV_CO_CI_U32_dpp_gfx11: |
814 | case AMDGPU::V_CNDMASK_B32_dpp8_gfx11: |
815 | case AMDGPU::V_ADD_CO_CI_U32_dpp8_gfx11: |
816 | case AMDGPU::V_SUB_CO_CI_U32_dpp8_gfx11: |
817 | case AMDGPU::V_SUBREV_CO_CI_U32_dpp8_gfx11: |
818 | case AMDGPU::V_CNDMASK_B32_e32_gfx12: |
819 | case AMDGPU::V_ADD_CO_CI_U32_e32_gfx12: |
820 | case AMDGPU::V_SUB_CO_CI_U32_e32_gfx12: |
821 | case AMDGPU::V_SUBREV_CO_CI_U32_e32_gfx12: |
822 | case AMDGPU::V_CNDMASK_B32_dpp_gfx12: |
823 | case AMDGPU::V_ADD_CO_CI_U32_dpp_gfx12: |
824 | case AMDGPU::V_SUB_CO_CI_U32_dpp_gfx12: |
825 | case AMDGPU::V_SUBREV_CO_CI_U32_dpp_gfx12: |
826 | case AMDGPU::V_CNDMASK_B32_dpp8_gfx12: |
827 | case AMDGPU::V_ADD_CO_CI_U32_dpp8_gfx12: |
828 | case AMDGPU::V_SUB_CO_CI_U32_dpp8_gfx12: |
829 | case AMDGPU::V_SUBREV_CO_CI_U32_dpp8_gfx12: |
830 | |
831 | case AMDGPU::V_CNDMASK_B32_e32_gfx6_gfx7: |
832 | case AMDGPU::V_CNDMASK_B32_e32_vi: |
833 | if ((int)OpNo == AMDGPU::getNamedOperandIdx(Opcode: MI->getOpcode(), |
834 | Name: AMDGPU::OpName::src1)) |
835 | printDefaultVccOperand(FirstOperand: OpNo == 0, STI, O); |
836 | break; |
837 | } |
838 | |
839 | if (Desc.TSFlags & SIInstrFlags::MTBUF) { |
840 | int SOffsetIdx = |
841 | AMDGPU::getNamedOperandIdx(Opcode: MI->getOpcode(), Name: AMDGPU::OpName::soffset); |
842 | assert(SOffsetIdx != -1); |
843 | if ((int)OpNo == SOffsetIdx) |
844 | printSymbolicFormat(MI, STI, O); |
845 | } |
846 | } |
847 | |
848 | void AMDGPUInstPrinter::printOperandAndFPInputMods(const MCInst *MI, |
849 | unsigned OpNo, |
850 | const MCSubtargetInfo &STI, |
851 | raw_ostream &O) { |
852 | const MCInstrDesc &Desc = MII.get(Opcode: MI->getOpcode()); |
853 | if (needsImpliedVcc(Desc, OpNo)) |
854 | printDefaultVccOperand(FirstOperand: true, STI, O); |
855 | |
856 | unsigned InputModifiers = MI->getOperand(i: OpNo).getImm(); |
857 | |
858 | // Use 'neg(...)' instead of '-' to avoid ambiguity. |
859 | // This is important for integer literals because |
860 | // -1 is not the same value as neg(1). |
861 | bool NegMnemo = false; |
862 | |
863 | if (InputModifiers & SISrcMods::NEG) { |
864 | if (OpNo + 1 < MI->getNumOperands() && |
865 | (InputModifiers & SISrcMods::ABS) == 0) { |
866 | const MCOperand &Op = MI->getOperand(i: OpNo + 1); |
867 | NegMnemo = Op.isImm() || Op.isDFPImm(); |
868 | } |
869 | if (NegMnemo) { |
870 | O << "neg(" ; |
871 | } else { |
872 | O << '-'; |
873 | } |
874 | } |
875 | |
876 | if (InputModifiers & SISrcMods::ABS) |
877 | O << '|'; |
878 | printRegularOperand(MI, OpNo: OpNo + 1, STI, O); |
879 | if (InputModifiers & SISrcMods::ABS) |
880 | O << '|'; |
881 | |
882 | if (NegMnemo) { |
883 | O << ')'; |
884 | } |
885 | |
886 | // Print default vcc/vcc_lo operand of VOP2b. |
887 | switch (MI->getOpcode()) { |
888 | default: |
889 | break; |
890 | |
891 | case AMDGPU::V_CNDMASK_B32_sdwa_gfx10: |
892 | case AMDGPU::V_CNDMASK_B32_dpp_gfx10: |
893 | case AMDGPU::V_CNDMASK_B32_dpp_gfx11: |
894 | if ((int)OpNo + 1 == |
895 | AMDGPU::getNamedOperandIdx(Opcode: MI->getOpcode(), Name: AMDGPU::OpName::src1)) |
896 | printDefaultVccOperand(FirstOperand: OpNo == 0, STI, O); |
897 | break; |
898 | } |
899 | } |
900 | |
901 | void AMDGPUInstPrinter::printOperandAndIntInputMods(const MCInst *MI, |
902 | unsigned OpNo, |
903 | const MCSubtargetInfo &STI, |
904 | raw_ostream &O) { |
905 | const MCInstrDesc &Desc = MII.get(Opcode: MI->getOpcode()); |
906 | if (needsImpliedVcc(Desc, OpNo)) |
907 | printDefaultVccOperand(FirstOperand: true, STI, O); |
908 | |
909 | unsigned InputModifiers = MI->getOperand(i: OpNo).getImm(); |
910 | if (InputModifiers & SISrcMods::SEXT) |
911 | O << "sext(" ; |
912 | printRegularOperand(MI, OpNo: OpNo + 1, STI, O); |
913 | if (InputModifiers & SISrcMods::SEXT) |
914 | O << ')'; |
915 | |
916 | // Print default vcc/vcc_lo operand of VOP2b. |
917 | switch (MI->getOpcode()) { |
918 | default: break; |
919 | |
920 | case AMDGPU::V_ADD_CO_CI_U32_sdwa_gfx10: |
921 | case AMDGPU::V_SUB_CO_CI_U32_sdwa_gfx10: |
922 | case AMDGPU::V_SUBREV_CO_CI_U32_sdwa_gfx10: |
923 | if ((int)OpNo + 1 == AMDGPU::getNamedOperandIdx(Opcode: MI->getOpcode(), |
924 | Name: AMDGPU::OpName::src1)) |
925 | printDefaultVccOperand(FirstOperand: OpNo == 0, STI, O); |
926 | break; |
927 | } |
928 | } |
929 | |
930 | void AMDGPUInstPrinter::printDPP8(const MCInst *MI, unsigned OpNo, |
931 | const MCSubtargetInfo &STI, |
932 | raw_ostream &O) { |
933 | if (!AMDGPU::isGFX10Plus(STI)) |
934 | llvm_unreachable("dpp8 is not supported on ASICs earlier than GFX10" ); |
935 | |
936 | unsigned Imm = MI->getOperand(i: OpNo).getImm(); |
937 | O << "dpp8:[" << formatDec(Value: Imm & 0x7); |
938 | for (size_t i = 1; i < 8; ++i) { |
939 | O << ',' << formatDec(Value: (Imm >> (3 * i)) & 0x7); |
940 | } |
941 | O << ']'; |
942 | } |
943 | |
944 | void AMDGPUInstPrinter::printDPPCtrl(const MCInst *MI, unsigned OpNo, |
945 | const MCSubtargetInfo &STI, |
946 | raw_ostream &O) { |
947 | using namespace AMDGPU::DPP; |
948 | |
949 | unsigned Imm = MI->getOperand(i: OpNo).getImm(); |
950 | const MCInstrDesc &Desc = MII.get(Opcode: MI->getOpcode()); |
951 | |
952 | if (!AMDGPU::isLegalDPALU_DPPControl(DC: Imm) && AMDGPU::isDPALU_DPP(OpDesc: Desc)) { |
953 | O << " /* DP ALU dpp only supports row_newbcast */" ; |
954 | return; |
955 | } |
956 | if (Imm <= DppCtrl::QUAD_PERM_LAST) { |
957 | O << "quad_perm:[" ; |
958 | O << formatDec(Value: Imm & 0x3) << ','; |
959 | O << formatDec(Value: (Imm & 0xc) >> 2) << ','; |
960 | O << formatDec(Value: (Imm & 0x30) >> 4) << ','; |
961 | O << formatDec(Value: (Imm & 0xc0) >> 6) << ']'; |
962 | } else if ((Imm >= DppCtrl::ROW_SHL_FIRST) && |
963 | (Imm <= DppCtrl::ROW_SHL_LAST)) { |
964 | O << "row_shl:" << formatDec(Value: Imm - DppCtrl::ROW_SHL0); |
965 | } else if ((Imm >= DppCtrl::ROW_SHR_FIRST) && |
966 | (Imm <= DppCtrl::ROW_SHR_LAST)) { |
967 | O << "row_shr:" << formatDec(Value: Imm - DppCtrl::ROW_SHR0); |
968 | } else if ((Imm >= DppCtrl::ROW_ROR_FIRST) && |
969 | (Imm <= DppCtrl::ROW_ROR_LAST)) { |
970 | O << "row_ror:" << formatDec(Value: Imm - DppCtrl::ROW_ROR0); |
971 | } else if (Imm == DppCtrl::WAVE_SHL1) { |
972 | if (AMDGPU::isGFX10Plus(STI)) { |
973 | O << "/* wave_shl is not supported starting from GFX10 */" ; |
974 | return; |
975 | } |
976 | O << "wave_shl:1" ; |
977 | } else if (Imm == DppCtrl::WAVE_ROL1) { |
978 | if (AMDGPU::isGFX10Plus(STI)) { |
979 | O << "/* wave_rol is not supported starting from GFX10 */" ; |
980 | return; |
981 | } |
982 | O << "wave_rol:1" ; |
983 | } else if (Imm == DppCtrl::WAVE_SHR1) { |
984 | if (AMDGPU::isGFX10Plus(STI)) { |
985 | O << "/* wave_shr is not supported starting from GFX10 */" ; |
986 | return; |
987 | } |
988 | O << "wave_shr:1" ; |
989 | } else if (Imm == DppCtrl::WAVE_ROR1) { |
990 | if (AMDGPU::isGFX10Plus(STI)) { |
991 | O << "/* wave_ror is not supported starting from GFX10 */" ; |
992 | return; |
993 | } |
994 | O << "wave_ror:1" ; |
995 | } else if (Imm == DppCtrl::ROW_MIRROR) { |
996 | O << "row_mirror" ; |
997 | } else if (Imm == DppCtrl::ROW_HALF_MIRROR) { |
998 | O << "row_half_mirror" ; |
999 | } else if (Imm == DppCtrl::BCAST15) { |
1000 | if (AMDGPU::isGFX10Plus(STI)) { |
1001 | O << "/* row_bcast is not supported starting from GFX10 */" ; |
1002 | return; |
1003 | } |
1004 | O << "row_bcast:15" ; |
1005 | } else if (Imm == DppCtrl::BCAST31) { |
1006 | if (AMDGPU::isGFX10Plus(STI)) { |
1007 | O << "/* row_bcast is not supported starting from GFX10 */" ; |
1008 | return; |
1009 | } |
1010 | O << "row_bcast:31" ; |
1011 | } else if ((Imm >= DppCtrl::ROW_SHARE_FIRST) && |
1012 | (Imm <= DppCtrl::ROW_SHARE_LAST)) { |
1013 | if (AMDGPU::isGFX90A(STI)) { |
1014 | O << "row_newbcast:" ; |
1015 | } else if (AMDGPU::isGFX10Plus(STI)) { |
1016 | O << "row_share:" ; |
1017 | } else { |
1018 | O << " /* row_newbcast/row_share is not supported on ASICs earlier " |
1019 | "than GFX90A/GFX10 */" ; |
1020 | return; |
1021 | } |
1022 | O << formatDec(Value: Imm - DppCtrl::ROW_SHARE_FIRST); |
1023 | } else if ((Imm >= DppCtrl::ROW_XMASK_FIRST) && |
1024 | (Imm <= DppCtrl::ROW_XMASK_LAST)) { |
1025 | if (!AMDGPU::isGFX10Plus(STI)) { |
1026 | O << "/* row_xmask is not supported on ASICs earlier than GFX10 */" ; |
1027 | return; |
1028 | } |
1029 | O << "row_xmask:" << formatDec(Value: Imm - DppCtrl::ROW_XMASK_FIRST); |
1030 | } else { |
1031 | O << "/* Invalid dpp_ctrl value */" ; |
1032 | } |
1033 | } |
1034 | |
1035 | void AMDGPUInstPrinter::printDppBoundCtrl(const MCInst *MI, unsigned OpNo, |
1036 | const MCSubtargetInfo &STI, |
1037 | raw_ostream &O) { |
1038 | unsigned Imm = MI->getOperand(i: OpNo).getImm(); |
1039 | if (Imm) { |
1040 | O << " bound_ctrl:1" ; |
1041 | } |
1042 | } |
1043 | |
1044 | void AMDGPUInstPrinter::printDppFI(const MCInst *MI, unsigned OpNo, |
1045 | const MCSubtargetInfo &STI, raw_ostream &O) { |
1046 | using namespace llvm::AMDGPU::DPP; |
1047 | unsigned Imm = MI->getOperand(i: OpNo).getImm(); |
1048 | if (Imm == DPP_FI_1 || Imm == DPP8_FI_1) { |
1049 | O << " fi:1" ; |
1050 | } |
1051 | } |
1052 | |
1053 | void AMDGPUInstPrinter::printSDWASel(const MCInst *MI, unsigned OpNo, |
1054 | raw_ostream &O) { |
1055 | using namespace llvm::AMDGPU::SDWA; |
1056 | |
1057 | unsigned Imm = MI->getOperand(i: OpNo).getImm(); |
1058 | switch (Imm) { |
1059 | case SdwaSel::BYTE_0: O << "BYTE_0" ; break; |
1060 | case SdwaSel::BYTE_1: O << "BYTE_1" ; break; |
1061 | case SdwaSel::BYTE_2: O << "BYTE_2" ; break; |
1062 | case SdwaSel::BYTE_3: O << "BYTE_3" ; break; |
1063 | case SdwaSel::WORD_0: O << "WORD_0" ; break; |
1064 | case SdwaSel::WORD_1: O << "WORD_1" ; break; |
1065 | case SdwaSel::DWORD: O << "DWORD" ; break; |
1066 | default: llvm_unreachable("Invalid SDWA data select operand" ); |
1067 | } |
1068 | } |
1069 | |
1070 | void AMDGPUInstPrinter::printSDWADstSel(const MCInst *MI, unsigned OpNo, |
1071 | const MCSubtargetInfo &STI, |
1072 | raw_ostream &O) { |
1073 | O << "dst_sel:" ; |
1074 | printSDWASel(MI, OpNo, O); |
1075 | } |
1076 | |
1077 | void AMDGPUInstPrinter::printSDWASrc0Sel(const MCInst *MI, unsigned OpNo, |
1078 | const MCSubtargetInfo &STI, |
1079 | raw_ostream &O) { |
1080 | O << "src0_sel:" ; |
1081 | printSDWASel(MI, OpNo, O); |
1082 | } |
1083 | |
1084 | void AMDGPUInstPrinter::printSDWASrc1Sel(const MCInst *MI, unsigned OpNo, |
1085 | const MCSubtargetInfo &STI, |
1086 | raw_ostream &O) { |
1087 | O << "src1_sel:" ; |
1088 | printSDWASel(MI, OpNo, O); |
1089 | } |
1090 | |
1091 | void AMDGPUInstPrinter::printSDWADstUnused(const MCInst *MI, unsigned OpNo, |
1092 | const MCSubtargetInfo &STI, |
1093 | raw_ostream &O) { |
1094 | using namespace llvm::AMDGPU::SDWA; |
1095 | |
1096 | O << "dst_unused:" ; |
1097 | unsigned Imm = MI->getOperand(i: OpNo).getImm(); |
1098 | switch (Imm) { |
1099 | case DstUnused::UNUSED_PAD: O << "UNUSED_PAD" ; break; |
1100 | case DstUnused::UNUSED_SEXT: O << "UNUSED_SEXT" ; break; |
1101 | case DstUnused::UNUSED_PRESERVE: O << "UNUSED_PRESERVE" ; break; |
1102 | default: llvm_unreachable("Invalid SDWA dest_unused operand" ); |
1103 | } |
1104 | } |
1105 | |
1106 | void AMDGPUInstPrinter::printExpSrcN(const MCInst *MI, unsigned OpNo, |
1107 | const MCSubtargetInfo &STI, raw_ostream &O, |
1108 | unsigned N) { |
1109 | unsigned Opc = MI->getOpcode(); |
1110 | int EnIdx = AMDGPU::getNamedOperandIdx(Opcode: Opc, Name: AMDGPU::OpName::en); |
1111 | unsigned En = MI->getOperand(i: EnIdx).getImm(); |
1112 | |
1113 | int ComprIdx = AMDGPU::getNamedOperandIdx(Opcode: Opc, Name: AMDGPU::OpName::compr); |
1114 | |
1115 | // If compr is set, print as src0, src0, src1, src1 |
1116 | if (MI->getOperand(i: ComprIdx).getImm()) |
1117 | OpNo = OpNo - N + N / 2; |
1118 | |
1119 | if (En & (1 << N)) |
1120 | printRegOperand(Reg: MI->getOperand(i: OpNo).getReg(), O, MRI); |
1121 | else |
1122 | O << "off" ; |
1123 | } |
1124 | |
1125 | void AMDGPUInstPrinter::printExpSrc0(const MCInst *MI, unsigned OpNo, |
1126 | const MCSubtargetInfo &STI, |
1127 | raw_ostream &O) { |
1128 | printExpSrcN(MI, OpNo, STI, O, N: 0); |
1129 | } |
1130 | |
1131 | void AMDGPUInstPrinter::printExpSrc1(const MCInst *MI, unsigned OpNo, |
1132 | const MCSubtargetInfo &STI, |
1133 | raw_ostream &O) { |
1134 | printExpSrcN(MI, OpNo, STI, O, N: 1); |
1135 | } |
1136 | |
1137 | void AMDGPUInstPrinter::printExpSrc2(const MCInst *MI, unsigned OpNo, |
1138 | const MCSubtargetInfo &STI, |
1139 | raw_ostream &O) { |
1140 | printExpSrcN(MI, OpNo, STI, O, N: 2); |
1141 | } |
1142 | |
1143 | void AMDGPUInstPrinter::printExpSrc3(const MCInst *MI, unsigned OpNo, |
1144 | const MCSubtargetInfo &STI, |
1145 | raw_ostream &O) { |
1146 | printExpSrcN(MI, OpNo, STI, O, N: 3); |
1147 | } |
1148 | |
1149 | void AMDGPUInstPrinter::printExpTgt(const MCInst *MI, unsigned OpNo, |
1150 | const MCSubtargetInfo &STI, |
1151 | raw_ostream &O) { |
1152 | using namespace llvm::AMDGPU::Exp; |
1153 | |
1154 | // This is really a 6 bit field. |
1155 | unsigned Id = MI->getOperand(i: OpNo).getImm() & ((1 << 6) - 1); |
1156 | |
1157 | int Index; |
1158 | StringRef TgtName; |
1159 | if (getTgtName(Id, Name&: TgtName, Index) && isSupportedTgtId(Id, STI)) { |
1160 | O << ' ' << TgtName; |
1161 | if (Index >= 0) |
1162 | O << Index; |
1163 | } else { |
1164 | O << " invalid_target_" << Id; |
1165 | } |
1166 | } |
1167 | |
1168 | static bool allOpsDefaultValue(const int* Ops, int NumOps, int Mod, |
1169 | bool IsPacked, bool HasDstSel) { |
1170 | int DefaultValue = IsPacked && (Mod == SISrcMods::OP_SEL_1); |
1171 | |
1172 | for (int I = 0; I < NumOps; ++I) { |
1173 | if (!!(Ops[I] & Mod) != DefaultValue) |
1174 | return false; |
1175 | } |
1176 | |
1177 | if (HasDstSel && (Ops[0] & SISrcMods::DST_OP_SEL) != 0) |
1178 | return false; |
1179 | |
1180 | return true; |
1181 | } |
1182 | |
1183 | void AMDGPUInstPrinter::printPackedModifier(const MCInst *MI, |
1184 | StringRef Name, |
1185 | unsigned Mod, |
1186 | raw_ostream &O) { |
1187 | unsigned Opc = MI->getOpcode(); |
1188 | int NumOps = 0; |
1189 | int Ops[3]; |
1190 | |
1191 | std::pair<AMDGPU::OpName, AMDGPU::OpName> MOps[] = { |
1192 | {AMDGPU::OpName::src0_modifiers, AMDGPU::OpName::src0}, |
1193 | {AMDGPU::OpName::src1_modifiers, AMDGPU::OpName::src1}, |
1194 | {AMDGPU::OpName::src2_modifiers, AMDGPU::OpName::src2}}; |
1195 | int DefaultValue = (Mod == SISrcMods::OP_SEL_1); |
1196 | |
1197 | for (auto [SrcMod, Src] : MOps) { |
1198 | if (!AMDGPU::hasNamedOperand(Opcode: Opc, NamedIdx: Src)) |
1199 | break; |
1200 | |
1201 | int ModIdx = AMDGPU::getNamedOperandIdx(Opcode: Opc, Name: SrcMod); |
1202 | Ops[NumOps++] = |
1203 | (ModIdx != -1) ? MI->getOperand(i: ModIdx).getImm() : DefaultValue; |
1204 | } |
1205 | |
1206 | const bool HasDst = |
1207 | (AMDGPU::getNamedOperandIdx(Opcode: Opc, Name: AMDGPU::OpName::vdst) != -1) || |
1208 | (AMDGPU::getNamedOperandIdx(Opcode: Opc, Name: AMDGPU::OpName::sdst) != -1); |
1209 | |
1210 | // Print three values of neg/opsel for wmma instructions (prints 0 when there |
1211 | // is no src_modifier operand instead of not printing anything). |
1212 | if (MII.get(Opcode: MI->getOpcode()).TSFlags & SIInstrFlags::IsSWMMAC || |
1213 | MII.get(Opcode: MI->getOpcode()).TSFlags & SIInstrFlags::IsWMMA) { |
1214 | NumOps = 0; |
1215 | int DefaultValue = Mod == SISrcMods::OP_SEL_1; |
1216 | for (AMDGPU::OpName OpName : |
1217 | {AMDGPU::OpName::src0_modifiers, AMDGPU::OpName::src1_modifiers, |
1218 | AMDGPU::OpName::src2_modifiers}) { |
1219 | int Idx = AMDGPU::getNamedOperandIdx(Opcode: Opc, Name: OpName); |
1220 | if (Idx != -1) |
1221 | Ops[NumOps++] = MI->getOperand(i: Idx).getImm(); |
1222 | else |
1223 | Ops[NumOps++] = DefaultValue; |
1224 | } |
1225 | } |
1226 | |
1227 | const bool HasDstSel = |
1228 | HasDst && NumOps > 0 && Mod == SISrcMods::OP_SEL_0 && |
1229 | MII.get(Opcode: MI->getOpcode()).TSFlags & SIInstrFlags::VOP3_OPSEL; |
1230 | |
1231 | const bool IsPacked = |
1232 | MII.get(Opcode: MI->getOpcode()).TSFlags & SIInstrFlags::IsPacked; |
1233 | |
1234 | if (allOpsDefaultValue(Ops, NumOps, Mod, IsPacked, HasDstSel)) |
1235 | return; |
1236 | |
1237 | O << Name; |
1238 | for (int I = 0; I < NumOps; ++I) { |
1239 | if (I != 0) |
1240 | O << ','; |
1241 | |
1242 | O << !!(Ops[I] & Mod); |
1243 | } |
1244 | |
1245 | if (HasDstSel) { |
1246 | O << ',' << !!(Ops[0] & SISrcMods::DST_OP_SEL); |
1247 | } |
1248 | |
1249 | O << ']'; |
1250 | } |
1251 | |
1252 | void AMDGPUInstPrinter::printOpSel(const MCInst *MI, unsigned, |
1253 | const MCSubtargetInfo &STI, |
1254 | raw_ostream &O) { |
1255 | unsigned Opc = MI->getOpcode(); |
1256 | if (isCvt_F32_Fp8_Bf8_e64(Opc)) { |
1257 | auto SrcMod = |
1258 | AMDGPU::getNamedOperandIdx(Opcode: Opc, Name: AMDGPU::OpName::src0_modifiers); |
1259 | unsigned Mod = MI->getOperand(i: SrcMod).getImm(); |
1260 | unsigned Index0 = !!(Mod & SISrcMods::OP_SEL_0); |
1261 | unsigned Index1 = !!(Mod & SISrcMods::OP_SEL_1); |
1262 | if (Index0 || Index1) |
1263 | O << " op_sel:[" << Index0 << ',' << Index1 << ']'; |
1264 | return; |
1265 | } |
1266 | if (isPermlane16(Opc)) { |
1267 | auto FIN = AMDGPU::getNamedOperandIdx(Opcode: Opc, Name: AMDGPU::OpName::src0_modifiers); |
1268 | auto BCN = AMDGPU::getNamedOperandIdx(Opcode: Opc, Name: AMDGPU::OpName::src1_modifiers); |
1269 | unsigned FI = !!(MI->getOperand(i: FIN).getImm() & SISrcMods::OP_SEL_0); |
1270 | unsigned BC = !!(MI->getOperand(i: BCN).getImm() & SISrcMods::OP_SEL_0); |
1271 | if (FI || BC) |
1272 | O << " op_sel:[" << FI << ',' << BC << ']'; |
1273 | return; |
1274 | } |
1275 | |
1276 | printPackedModifier(MI, Name: " op_sel:[" , Mod: SISrcMods::OP_SEL_0, O); |
1277 | } |
1278 | |
1279 | void AMDGPUInstPrinter::printOpSelHi(const MCInst *MI, unsigned OpNo, |
1280 | const MCSubtargetInfo &STI, |
1281 | raw_ostream &O) { |
1282 | printPackedModifier(MI, Name: " op_sel_hi:[" , Mod: SISrcMods::OP_SEL_1, O); |
1283 | } |
1284 | |
1285 | void AMDGPUInstPrinter::printNegLo(const MCInst *MI, unsigned OpNo, |
1286 | const MCSubtargetInfo &STI, |
1287 | raw_ostream &O) { |
1288 | printPackedModifier(MI, Name: " neg_lo:[" , Mod: SISrcMods::NEG, O); |
1289 | } |
1290 | |
1291 | void AMDGPUInstPrinter::printNegHi(const MCInst *MI, unsigned OpNo, |
1292 | const MCSubtargetInfo &STI, |
1293 | raw_ostream &O) { |
1294 | printPackedModifier(MI, Name: " neg_hi:[" , Mod: SISrcMods::NEG_HI, O); |
1295 | } |
1296 | |
1297 | void AMDGPUInstPrinter::printIndexKey8bit(const MCInst *MI, unsigned OpNo, |
1298 | const MCSubtargetInfo &STI, |
1299 | raw_ostream &O) { |
1300 | auto Imm = MI->getOperand(i: OpNo).getImm() & 0x7; |
1301 | if (Imm == 0) |
1302 | return; |
1303 | |
1304 | O << " index_key:" << Imm; |
1305 | } |
1306 | |
1307 | void AMDGPUInstPrinter::printIndexKey16bit(const MCInst *MI, unsigned OpNo, |
1308 | const MCSubtargetInfo &STI, |
1309 | raw_ostream &O) { |
1310 | auto Imm = MI->getOperand(i: OpNo).getImm() & 0x7; |
1311 | if (Imm == 0) |
1312 | return; |
1313 | |
1314 | O << " index_key:" << Imm; |
1315 | } |
1316 | |
1317 | void AMDGPUInstPrinter::printInterpSlot(const MCInst *MI, unsigned OpNum, |
1318 | const MCSubtargetInfo &STI, |
1319 | raw_ostream &O) { |
1320 | unsigned Imm = MI->getOperand(i: OpNum).getImm(); |
1321 | switch (Imm) { |
1322 | case 0: |
1323 | O << "p10" ; |
1324 | break; |
1325 | case 1: |
1326 | O << "p20" ; |
1327 | break; |
1328 | case 2: |
1329 | O << "p0" ; |
1330 | break; |
1331 | default: |
1332 | O << "invalid_param_" << Imm; |
1333 | } |
1334 | } |
1335 | |
1336 | void AMDGPUInstPrinter::printInterpAttr(const MCInst *MI, unsigned OpNum, |
1337 | const MCSubtargetInfo &STI, |
1338 | raw_ostream &O) { |
1339 | unsigned Attr = MI->getOperand(i: OpNum).getImm(); |
1340 | O << "attr" << Attr; |
1341 | } |
1342 | |
1343 | void AMDGPUInstPrinter::printInterpAttrChan(const MCInst *MI, unsigned OpNum, |
1344 | const MCSubtargetInfo &STI, |
1345 | raw_ostream &O) { |
1346 | unsigned Chan = MI->getOperand(i: OpNum).getImm(); |
1347 | O << '.' << "xyzw" [Chan & 0x3]; |
1348 | } |
1349 | |
1350 | void AMDGPUInstPrinter::printGPRIdxMode(const MCInst *MI, unsigned OpNo, |
1351 | const MCSubtargetInfo &STI, |
1352 | raw_ostream &O) { |
1353 | using namespace llvm::AMDGPU::VGPRIndexMode; |
1354 | unsigned Val = MI->getOperand(i: OpNo).getImm(); |
1355 | |
1356 | if ((Val & ~ENABLE_MASK) != 0) { |
1357 | O << formatHex(Value: static_cast<uint64_t>(Val)); |
1358 | } else { |
1359 | O << "gpr_idx(" ; |
1360 | bool NeedComma = false; |
1361 | for (unsigned ModeId = ID_MIN; ModeId <= ID_MAX; ++ModeId) { |
1362 | if (Val & (1 << ModeId)) { |
1363 | if (NeedComma) |
1364 | O << ','; |
1365 | O << IdSymbolic[ModeId]; |
1366 | NeedComma = true; |
1367 | } |
1368 | } |
1369 | O << ')'; |
1370 | } |
1371 | } |
1372 | |
1373 | void AMDGPUInstPrinter::printMemOperand(const MCInst *MI, unsigned OpNo, |
1374 | const MCSubtargetInfo &STI, |
1375 | raw_ostream &O) { |
1376 | printRegularOperand(MI, OpNo, STI, O); |
1377 | O << ", " ; |
1378 | printRegularOperand(MI, OpNo: OpNo + 1, STI, O); |
1379 | } |
1380 | |
1381 | void AMDGPUInstPrinter::printIfSet(const MCInst *MI, unsigned OpNo, |
1382 | raw_ostream &O, StringRef Asm, |
1383 | StringRef Default) { |
1384 | const MCOperand &Op = MI->getOperand(i: OpNo); |
1385 | assert(Op.isImm()); |
1386 | if (Op.getImm() == 1) { |
1387 | O << Asm; |
1388 | } else { |
1389 | O << Default; |
1390 | } |
1391 | } |
1392 | |
1393 | void AMDGPUInstPrinter::printIfSet(const MCInst *MI, unsigned OpNo, |
1394 | raw_ostream &O, char Asm) { |
1395 | const MCOperand &Op = MI->getOperand(i: OpNo); |
1396 | assert(Op.isImm()); |
1397 | if (Op.getImm() == 1) |
1398 | O << Asm; |
1399 | } |
1400 | |
1401 | void AMDGPUInstPrinter::printOModSI(const MCInst *MI, unsigned OpNo, |
1402 | const MCSubtargetInfo &STI, |
1403 | raw_ostream &O) { |
1404 | int Imm = MI->getOperand(i: OpNo).getImm(); |
1405 | if (Imm == SIOutMods::MUL2) |
1406 | O << " mul:2" ; |
1407 | else if (Imm == SIOutMods::MUL4) |
1408 | O << " mul:4" ; |
1409 | else if (Imm == SIOutMods::DIV2) |
1410 | O << " div:2" ; |
1411 | } |
1412 | |
1413 | void AMDGPUInstPrinter::printSendMsg(const MCInst *MI, unsigned OpNo, |
1414 | const MCSubtargetInfo &STI, |
1415 | raw_ostream &O) { |
1416 | using namespace llvm::AMDGPU::SendMsg; |
1417 | |
1418 | const unsigned Imm16 = MI->getOperand(i: OpNo).getImm(); |
1419 | |
1420 | uint16_t MsgId; |
1421 | uint16_t OpId; |
1422 | uint16_t StreamId; |
1423 | decodeMsg(Val: Imm16, MsgId, OpId, StreamId, STI); |
1424 | |
1425 | StringRef MsgName = getMsgName(Encoding: MsgId, STI); |
1426 | |
1427 | if (!MsgName.empty() && isValidMsgOp(MsgId, OpId, STI) && |
1428 | isValidMsgStream(MsgId, OpId, StreamId, STI)) { |
1429 | O << "sendmsg(" << MsgName; |
1430 | if (msgRequiresOp(MsgId, STI)) { |
1431 | O << ", " << getMsgOpName(MsgId, Encoding: OpId, STI); |
1432 | if (msgSupportsStream(MsgId, OpId, STI)) { |
1433 | O << ", " << StreamId; |
1434 | } |
1435 | } |
1436 | O << ')'; |
1437 | } else if (encodeMsg(MsgId, OpId, StreamId) == Imm16) { |
1438 | O << "sendmsg(" << MsgId << ", " << OpId << ", " << StreamId << ')'; |
1439 | } else { |
1440 | O << Imm16; // Unknown imm16 code. |
1441 | } |
1442 | } |
1443 | |
1444 | static void printSwizzleBitmask(const uint16_t AndMask, |
1445 | const uint16_t OrMask, |
1446 | const uint16_t XorMask, |
1447 | raw_ostream &O) { |
1448 | using namespace llvm::AMDGPU::Swizzle; |
1449 | |
1450 | uint16_t Probe0 = ((0 & AndMask) | OrMask) ^ XorMask; |
1451 | uint16_t Probe1 = ((BITMASK_MASK & AndMask) | OrMask) ^ XorMask; |
1452 | |
1453 | O << "\"" ; |
1454 | |
1455 | for (unsigned Mask = 1 << (BITMASK_WIDTH - 1); Mask > 0; Mask >>= 1) { |
1456 | uint16_t p0 = Probe0 & Mask; |
1457 | uint16_t p1 = Probe1 & Mask; |
1458 | |
1459 | if (p0 == p1) { |
1460 | if (p0 == 0) { |
1461 | O << "0" ; |
1462 | } else { |
1463 | O << "1" ; |
1464 | } |
1465 | } else { |
1466 | if (p0 == 0) { |
1467 | O << "p" ; |
1468 | } else { |
1469 | O << "i" ; |
1470 | } |
1471 | } |
1472 | } |
1473 | |
1474 | O << "\"" ; |
1475 | } |
1476 | |
1477 | void AMDGPUInstPrinter::printSwizzle(const MCInst *MI, unsigned OpNo, |
1478 | const MCSubtargetInfo &STI, |
1479 | raw_ostream &O) { |
1480 | using namespace llvm::AMDGPU::Swizzle; |
1481 | |
1482 | uint16_t Imm = MI->getOperand(i: OpNo).getImm(); |
1483 | if (Imm == 0) { |
1484 | return; |
1485 | } |
1486 | |
1487 | O << " offset:" ; |
1488 | |
1489 | // Rotate and FFT modes |
1490 | if (Imm >= ROTATE_MODE_LO && AMDGPU::isGFX9Plus(STI)) { |
1491 | if (Imm >= FFT_MODE_LO) { |
1492 | O << "swizzle(" << IdSymbolic[ID_FFT] << ',' << (Imm & FFT_SWIZZLE_MASK) |
1493 | << ')'; |
1494 | } else if (Imm >= ROTATE_MODE_LO) { |
1495 | O << "swizzle(" << IdSymbolic[ID_ROTATE] << ',' |
1496 | << ((Imm >> ROTATE_DIR_SHIFT) & ROTATE_DIR_MASK) << ',' |
1497 | << ((Imm >> ROTATE_SIZE_SHIFT) & ROTATE_SIZE_MASK) << ')'; |
1498 | } |
1499 | return; |
1500 | } |
1501 | |
1502 | // Basic mode |
1503 | if ((Imm & QUAD_PERM_ENC_MASK) == QUAD_PERM_ENC) { |
1504 | O << "swizzle(" << IdSymbolic[ID_QUAD_PERM]; |
1505 | for (unsigned I = 0; I < LANE_NUM; ++I) { |
1506 | O << "," ; |
1507 | O << formatDec(Value: Imm & LANE_MASK); |
1508 | Imm >>= LANE_SHIFT; |
1509 | } |
1510 | O << ")" ; |
1511 | |
1512 | } else if ((Imm & BITMASK_PERM_ENC_MASK) == BITMASK_PERM_ENC) { |
1513 | |
1514 | uint16_t AndMask = (Imm >> BITMASK_AND_SHIFT) & BITMASK_MASK; |
1515 | uint16_t OrMask = (Imm >> BITMASK_OR_SHIFT) & BITMASK_MASK; |
1516 | uint16_t XorMask = (Imm >> BITMASK_XOR_SHIFT) & BITMASK_MASK; |
1517 | |
1518 | if (AndMask == BITMASK_MAX && OrMask == 0 && llvm::popcount(Value: XorMask) == 1) { |
1519 | |
1520 | O << "swizzle(" << IdSymbolic[ID_SWAP]; |
1521 | O << "," ; |
1522 | O << formatDec(Value: XorMask); |
1523 | O << ")" ; |
1524 | |
1525 | } else if (AndMask == BITMASK_MAX && OrMask == 0 && XorMask > 0 && |
1526 | isPowerOf2_64(Value: XorMask + 1)) { |
1527 | |
1528 | O << "swizzle(" << IdSymbolic[ID_REVERSE]; |
1529 | O << "," ; |
1530 | O << formatDec(Value: XorMask + 1); |
1531 | O << ")" ; |
1532 | |
1533 | } else { |
1534 | |
1535 | uint16_t GroupSize = BITMASK_MAX - AndMask + 1; |
1536 | if (GroupSize > 1 && |
1537 | isPowerOf2_64(Value: GroupSize) && |
1538 | OrMask < GroupSize && |
1539 | XorMask == 0) { |
1540 | |
1541 | O << "swizzle(" << IdSymbolic[ID_BROADCAST]; |
1542 | O << "," ; |
1543 | O << formatDec(Value: GroupSize); |
1544 | O << "," ; |
1545 | O << formatDec(Value: OrMask); |
1546 | O << ")" ; |
1547 | |
1548 | } else { |
1549 | O << "swizzle(" << IdSymbolic[ID_BITMASK_PERM]; |
1550 | O << "," ; |
1551 | printSwizzleBitmask(AndMask, OrMask, XorMask, O); |
1552 | O << ")" ; |
1553 | } |
1554 | } |
1555 | } else { |
1556 | printU16ImmDecOperand(MI, OpNo, O); |
1557 | } |
1558 | } |
1559 | |
1560 | void AMDGPUInstPrinter::printSWaitCnt(const MCInst *MI, unsigned OpNo, |
1561 | const MCSubtargetInfo &STI, |
1562 | raw_ostream &O) { |
1563 | AMDGPU::IsaVersion ISA = AMDGPU::getIsaVersion(GPU: STI.getCPU()); |
1564 | |
1565 | unsigned SImm16 = MI->getOperand(i: OpNo).getImm(); |
1566 | unsigned Vmcnt, Expcnt, Lgkmcnt; |
1567 | decodeWaitcnt(Version: ISA, Waitcnt: SImm16, Vmcnt, Expcnt, Lgkmcnt); |
1568 | |
1569 | bool IsDefaultVmcnt = Vmcnt == getVmcntBitMask(Version: ISA); |
1570 | bool IsDefaultExpcnt = Expcnt == getExpcntBitMask(Version: ISA); |
1571 | bool IsDefaultLgkmcnt = Lgkmcnt == getLgkmcntBitMask(Version: ISA); |
1572 | bool PrintAll = IsDefaultVmcnt && IsDefaultExpcnt && IsDefaultLgkmcnt; |
1573 | |
1574 | bool NeedSpace = false; |
1575 | |
1576 | if (!IsDefaultVmcnt || PrintAll) { |
1577 | O << "vmcnt(" << Vmcnt << ')'; |
1578 | NeedSpace = true; |
1579 | } |
1580 | |
1581 | if (!IsDefaultExpcnt || PrintAll) { |
1582 | if (NeedSpace) |
1583 | O << ' '; |
1584 | O << "expcnt(" << Expcnt << ')'; |
1585 | NeedSpace = true; |
1586 | } |
1587 | |
1588 | if (!IsDefaultLgkmcnt || PrintAll) { |
1589 | if (NeedSpace) |
1590 | O << ' '; |
1591 | O << "lgkmcnt(" << Lgkmcnt << ')'; |
1592 | } |
1593 | } |
1594 | |
1595 | void AMDGPUInstPrinter::printDepCtr(const MCInst *MI, unsigned OpNo, |
1596 | const MCSubtargetInfo &STI, |
1597 | raw_ostream &O) { |
1598 | using namespace llvm::AMDGPU::DepCtr; |
1599 | |
1600 | uint64_t Imm16 = MI->getOperand(i: OpNo).getImm() & 0xffff; |
1601 | |
1602 | bool HasNonDefaultVal = false; |
1603 | if (isSymbolicDepCtrEncoding(Code: Imm16, HasNonDefaultVal, STI)) { |
1604 | int Id = 0; |
1605 | StringRef Name; |
1606 | unsigned Val; |
1607 | bool IsDefault; |
1608 | bool NeedSpace = false; |
1609 | while (decodeDepCtr(Code: Imm16, Id, Name, Val, IsDefault, STI)) { |
1610 | if (!IsDefault || !HasNonDefaultVal) { |
1611 | if (NeedSpace) |
1612 | O << ' '; |
1613 | O << Name << '(' << Val << ')'; |
1614 | NeedSpace = true; |
1615 | } |
1616 | } |
1617 | } else { |
1618 | O << formatHex(Value: Imm16); |
1619 | } |
1620 | } |
1621 | |
1622 | void AMDGPUInstPrinter::printSDelayALU(const MCInst *MI, unsigned OpNo, |
1623 | const MCSubtargetInfo &STI, |
1624 | raw_ostream &O) { |
1625 | const char *BadInstId = "/* invalid instid value */" ; |
1626 | static const std::array<const char *, 12> InstIds = { |
1627 | "NO_DEP" , "VALU_DEP_1" , "VALU_DEP_2" , |
1628 | "VALU_DEP_3" , "VALU_DEP_4" , "TRANS32_DEP_1" , |
1629 | "TRANS32_DEP_2" , "TRANS32_DEP_3" , "FMA_ACCUM_CYCLE_1" , |
1630 | "SALU_CYCLE_1" , "SALU_CYCLE_2" , "SALU_CYCLE_3" }; |
1631 | |
1632 | const char *BadInstSkip = "/* invalid instskip value */" ; |
1633 | static const std::array<const char *, 6> InstSkips = { |
1634 | "SAME" , "NEXT" , "SKIP_1" , "SKIP_2" , "SKIP_3" , "SKIP_4" }; |
1635 | |
1636 | unsigned SImm16 = MI->getOperand(i: OpNo).getImm(); |
1637 | const char *Prefix = "" ; |
1638 | |
1639 | unsigned Value = SImm16 & 0xF; |
1640 | if (Value) { |
1641 | const char *Name = Value < InstIds.size() ? InstIds[Value] : BadInstId; |
1642 | O << Prefix << "instid0(" << Name << ')'; |
1643 | Prefix = " | " ; |
1644 | } |
1645 | |
1646 | Value = (SImm16 >> 4) & 7; |
1647 | if (Value) { |
1648 | const char *Name = |
1649 | Value < InstSkips.size() ? InstSkips[Value] : BadInstSkip; |
1650 | O << Prefix << "instskip(" << Name << ')'; |
1651 | Prefix = " | " ; |
1652 | } |
1653 | |
1654 | Value = (SImm16 >> 7) & 0xF; |
1655 | if (Value) { |
1656 | const char *Name = Value < InstIds.size() ? InstIds[Value] : BadInstId; |
1657 | O << Prefix << "instid1(" << Name << ')'; |
1658 | Prefix = " | " ; |
1659 | } |
1660 | |
1661 | if (!*Prefix) |
1662 | O << "0" ; |
1663 | } |
1664 | |
1665 | void AMDGPUInstPrinter::printHwreg(const MCInst *MI, unsigned OpNo, |
1666 | const MCSubtargetInfo &STI, raw_ostream &O) { |
1667 | using namespace llvm::AMDGPU::Hwreg; |
1668 | unsigned Val = MI->getOperand(i: OpNo).getImm(); |
1669 | auto [Id, Offset, Width] = HwregEncoding::decode(Encoded: Val); |
1670 | StringRef HwRegName = getHwreg(Encoding: Id, STI); |
1671 | |
1672 | O << "hwreg(" ; |
1673 | if (!HwRegName.empty()) { |
1674 | O << HwRegName; |
1675 | } else { |
1676 | O << Id; |
1677 | } |
1678 | if (Width != HwregSize::Default || Offset != HwregOffset::Default) |
1679 | O << ", " << Offset << ", " << Width; |
1680 | O << ')'; |
1681 | } |
1682 | |
1683 | void AMDGPUInstPrinter::printEndpgm(const MCInst *MI, unsigned OpNo, |
1684 | const MCSubtargetInfo &STI, |
1685 | raw_ostream &O) { |
1686 | uint16_t Imm = MI->getOperand(i: OpNo).getImm(); |
1687 | if (Imm == 0) { |
1688 | return; |
1689 | } |
1690 | |
1691 | O << ' ' << formatDec(Value: Imm); |
1692 | } |
1693 | |
1694 | void AMDGPUInstPrinter::printNamedInt(const MCInst *MI, unsigned OpNo, |
1695 | const MCSubtargetInfo &STI, |
1696 | raw_ostream &O, StringRef Prefix, |
1697 | bool PrintInHex, bool AlwaysPrint) { |
1698 | int64_t V = MI->getOperand(i: OpNo).getImm(); |
1699 | if (AlwaysPrint || V != 0) |
1700 | O << ' ' << Prefix << ':' << (PrintInHex ? formatHex(Value: V) : formatDec(Value: V)); |
1701 | } |
1702 | |
1703 | void AMDGPUInstPrinter::printBitOp3(const MCInst *MI, unsigned OpNo, |
1704 | const MCSubtargetInfo &STI, |
1705 | raw_ostream &O) { |
1706 | uint8_t Imm = MI->getOperand(i: OpNo).getImm(); |
1707 | if (!Imm) |
1708 | return; |
1709 | |
1710 | O << " bitop3:" ; |
1711 | if (Imm <= 10) |
1712 | O << formatDec(Value: Imm); |
1713 | else |
1714 | O << formatHex(Value: static_cast<uint64_t>(Imm)); |
1715 | } |
1716 | |
1717 | #include "AMDGPUGenAsmWriter.inc" |
1718 | |