1//===- AMDGPUDisassembler.hpp - Disassembler for AMDGPU ISA -----*- C++ -*-===//
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///
11/// This file contains declaration for AMDGPU ISA disassembler
12//
13//===----------------------------------------------------------------------===//
14
15#ifndef LLVM_LIB_TARGET_AMDGPU_DISASSEMBLER_AMDGPUDISASSEMBLER_H
16#define LLVM_LIB_TARGET_AMDGPU_DISASSEMBLER_AMDGPUDISASSEMBLER_H
17
18#include "SIDefines.h"
19#include "llvm/ADT/APInt.h"
20#include "llvm/ADT/SmallString.h"
21#include "llvm/MC/MCDisassembler/MCDisassembler.h"
22#include "llvm/MC/MCInst.h"
23#include "llvm/MC/MCInstrInfo.h"
24#include "llvm/Support/DataExtractor.h"
25#include <memory>
26
27namespace llvm {
28
29class MCAsmInfo;
30class MCInst;
31class MCOperand;
32class MCSubtargetInfo;
33class Twine;
34
35// Exposes an interface expected by autogenerated code in
36// FixedLenDecoderEmitter
37class DecoderUInt128 {
38private:
39 uint64_t Lo = 0;
40 uint64_t Hi = 0;
41
42public:
43 DecoderUInt128() = default;
44 DecoderUInt128(uint64_t Lo, uint64_t Hi = 0) : Lo(Lo), Hi(Hi) {}
45 operator bool() const { return Lo || Hi; }
46 void insertBits(uint64_t SubBits, unsigned BitPosition, unsigned NumBits) {
47 assert(NumBits && NumBits <= 64);
48 assert(SubBits >> 1 >> (NumBits - 1) == 0);
49 assert(BitPosition < 128);
50 if (BitPosition < 64) {
51 Lo |= SubBits << BitPosition;
52 Hi |= SubBits >> 1 >> (63 - BitPosition);
53 } else {
54 Hi |= SubBits << (BitPosition - 64);
55 }
56 }
57 uint64_t extractBitsAsZExtValue(unsigned NumBits,
58 unsigned BitPosition) const {
59 assert(NumBits && NumBits <= 64);
60 assert(BitPosition < 128);
61 uint64_t Val;
62 if (BitPosition < 64)
63 Val = Lo >> BitPosition | Hi << 1 << (63 - BitPosition);
64 else
65 Val = Hi >> (BitPosition - 64);
66 return Val & ((uint64_t(2) << (NumBits - 1)) - 1);
67 }
68 DecoderUInt128 operator&(const DecoderUInt128 &RHS) const {
69 return DecoderUInt128(Lo & RHS.Lo, Hi & RHS.Hi);
70 }
71 DecoderUInt128 operator&(const uint64_t &RHS) const {
72 return *this & DecoderUInt128(RHS);
73 }
74 DecoderUInt128 operator~() const { return DecoderUInt128(~Lo, ~Hi); }
75 bool operator==(const DecoderUInt128 &RHS) {
76 return Lo == RHS.Lo && Hi == RHS.Hi;
77 }
78 bool operator!=(const DecoderUInt128 &RHS) {
79 return Lo != RHS.Lo || Hi != RHS.Hi;
80 }
81 bool operator!=(const int &RHS) {
82 return *this != DecoderUInt128(RHS);
83 }
84 friend raw_ostream &operator<<(raw_ostream &OS, const DecoderUInt128 &RHS) {
85 return OS << APInt(128, {RHS.Lo, RHS.Hi});
86 }
87};
88
89//===----------------------------------------------------------------------===//
90// AMDGPUDisassembler
91//===----------------------------------------------------------------------===//
92
93class AMDGPUDisassembler : public MCDisassembler {
94private:
95 std::unique_ptr<MCInstrInfo const> const MCII;
96 const MCRegisterInfo &MRI;
97 const MCAsmInfo &MAI;
98 const unsigned TargetMaxInstBytes;
99 mutable ArrayRef<uint8_t> Bytes;
100 mutable uint32_t Literal;
101 mutable uint64_t Literal64;
102 mutable bool HasLiteral;
103 mutable std::optional<bool> EnableWavefrontSize32;
104 unsigned CodeObjectVersion;
105 const MCExpr *UCVersionW64Expr;
106 const MCExpr *UCVersionW32Expr;
107 const MCExpr *UCVersionMDPExpr;
108
109 const MCExpr *createConstantSymbolExpr(StringRef Id, int64_t Val);
110
111public:
112 AMDGPUDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx,
113 MCInstrInfo const *MCII);
114 ~AMDGPUDisassembler() override = default;
115
116 void setABIVersion(unsigned Version) override;
117
118 DecodeStatus getInstruction(MCInst &MI, uint64_t &Size,
119 ArrayRef<uint8_t> Bytes, uint64_t Address,
120 raw_ostream &CS) const override;
121
122 const char* getRegClassName(unsigned RegClassID) const;
123
124 MCOperand createRegOperand(unsigned int RegId) const;
125 MCOperand createRegOperand(unsigned RegClassID, unsigned Val) const;
126 MCOperand createSRegOperand(unsigned SRegClassID, unsigned Val) const;
127 MCOperand createVGPR16Operand(unsigned RegIdx, bool IsHi) const;
128
129 MCOperand errOperand(unsigned V, const Twine& ErrMsg) const;
130
131 template <typename InsnType>
132 DecodeStatus tryDecodeInst(const uint8_t *Table, MCInst &MI, InsnType Inst,
133 uint64_t Address, raw_ostream &Comments) const {
134 assert(MI.getOpcode() == 0);
135 assert(MI.getNumOperands() == 0);
136 MCInst TmpInst;
137 HasLiteral = false;
138 const auto SavedBytes = Bytes;
139
140 SmallString<64> LocalComments;
141 raw_svector_ostream LocalCommentStream(LocalComments);
142 CommentStream = &LocalCommentStream;
143
144 DecodeStatus Res =
145 decodeInstruction(Table, TmpInst, Inst, Address, this, STI);
146
147 CommentStream = nullptr;
148
149 if (Res != Fail) {
150 MI = TmpInst;
151 Comments << LocalComments;
152 return MCDisassembler::Success;
153 }
154 Bytes = SavedBytes;
155 return MCDisassembler::Fail;
156 }
157
158 template <typename InsnType>
159 DecodeStatus tryDecodeInst(const uint8_t *Table1, const uint8_t *Table2,
160 MCInst &MI, InsnType Inst, uint64_t Address,
161 raw_ostream &Comments) const {
162 for (const uint8_t *T : {Table1, Table2}) {
163 if (DecodeStatus Res = tryDecodeInst(T, MI, Inst, Address, Comments))
164 return Res;
165 }
166 return MCDisassembler::Fail;
167 }
168
169 Expected<bool> onSymbolStart(SymbolInfoTy &Symbol, uint64_t &Size,
170 ArrayRef<uint8_t> Bytes,
171 uint64_t Address) const override;
172
173 Expected<bool> decodeKernelDescriptor(StringRef KdName,
174 ArrayRef<uint8_t> Bytes,
175 uint64_t KdAddress) const;
176
177 Expected<bool>
178 decodeKernelDescriptorDirective(DataExtractor::Cursor &Cursor,
179 ArrayRef<uint8_t> Bytes,
180 raw_string_ostream &KdStream) const;
181
182 /// Decode as directives that handle COMPUTE_PGM_RSRC1.
183 /// \param FourByteBuffer - Bytes holding contents of COMPUTE_PGM_RSRC1.
184 /// \param KdStream - Stream to write the disassembled directives to.
185 // NOLINTNEXTLINE(readability-identifier-naming)
186 Expected<bool> decodeCOMPUTE_PGM_RSRC1(uint32_t FourByteBuffer,
187 raw_string_ostream &KdStream) const;
188
189 /// Decode as directives that handle COMPUTE_PGM_RSRC2.
190 /// \param FourByteBuffer - Bytes holding contents of COMPUTE_PGM_RSRC2.
191 /// \param KdStream - Stream to write the disassembled directives to.
192 // NOLINTNEXTLINE(readability-identifier-naming)
193 Expected<bool> decodeCOMPUTE_PGM_RSRC2(uint32_t FourByteBuffer,
194 raw_string_ostream &KdStream) const;
195
196 /// Decode as directives that handle COMPUTE_PGM_RSRC3.
197 /// \param FourByteBuffer - Bytes holding contents of COMPUTE_PGM_RSRC3.
198 /// \param KdStream - Stream to write the disassembled directives to.
199 // NOLINTNEXTLINE(readability-identifier-naming)
200 Expected<bool> decodeCOMPUTE_PGM_RSRC3(uint32_t FourByteBuffer,
201 raw_string_ostream &KdStream) const;
202
203 void convertEXPInst(MCInst &MI) const;
204 void convertVINTERPInst(MCInst &MI) const;
205 void convertFMAanyK(MCInst &MI, int ImmLitIdx) const;
206 void convertSDWAInst(MCInst &MI) const;
207 void convertDPP8Inst(MCInst &MI) const;
208 void convertMIMGInst(MCInst &MI) const;
209 void convertVOP3DPPInst(MCInst &MI) const;
210 void convertVOP3PDPPInst(MCInst &MI) const;
211 void convertVOPCDPPInst(MCInst &MI) const;
212 void convertMacDPPInst(MCInst &MI) const;
213 void convertTrue16OpSel(MCInst &MI) const;
214
215 enum OpWidthTy {
216 OPW32,
217 OPW64,
218 OPW96,
219 OPW128,
220 OPW160,
221 OPW256,
222 OPW288,
223 OPW320,
224 OPW352,
225 OPW384,
226 OPW512,
227 OPW1024,
228 OPW16,
229 OPWV216,
230 OPWV232,
231 OPW_LAST_,
232 OPW_FIRST_ = OPW32
233 };
234
235 unsigned getVgprClassId(const OpWidthTy Width) const;
236 unsigned getAgprClassId(const OpWidthTy Width) const;
237 unsigned getSgprClassId(const OpWidthTy Width) const;
238 unsigned getTtmpClassId(const OpWidthTy Width) const;
239
240 static MCOperand decodeIntImmed(unsigned Imm);
241 static MCOperand decodeFPImmed(unsigned ImmWidth, unsigned Imm,
242 AMDGPU::OperandSemantics Sema);
243
244 MCOperand decodeMandatoryLiteralConstant(unsigned Imm) const;
245 MCOperand decodeLiteralConstant(bool ExtendFP64) const;
246
247 MCOperand decodeSrcOp(
248 const OpWidthTy Width, unsigned Val, bool MandatoryLiteral = false,
249 unsigned ImmWidth = 0,
250 AMDGPU::OperandSemantics Sema = AMDGPU::OperandSemantics::INT) const;
251
252 MCOperand decodeNonVGPRSrcOp(
253 const OpWidthTy Width, unsigned Val, bool MandatoryLiteral = false,
254 unsigned ImmWidth = 0,
255 AMDGPU::OperandSemantics Sema = AMDGPU::OperandSemantics::INT) const;
256
257 MCOperand decodeVOPDDstYOp(MCInst &Inst, unsigned Val) const;
258 MCOperand decodeSpecialReg32(unsigned Val) const;
259 MCOperand decodeSpecialReg64(unsigned Val) const;
260
261 MCOperand decodeSDWASrc(const OpWidthTy Width, unsigned Val,
262 unsigned ImmWidth,
263 AMDGPU::OperandSemantics Sema) const;
264 MCOperand decodeSDWASrc16(unsigned Val) const;
265 MCOperand decodeSDWASrc32(unsigned Val) const;
266 MCOperand decodeSDWAVopcDst(unsigned Val) const;
267
268 MCOperand decodeBoolReg(unsigned Val) const;
269 MCOperand decodeSplitBarrier(unsigned Val) const;
270 MCOperand decodeDpp8FI(unsigned Val) const;
271
272 MCOperand decodeVersionImm(unsigned Imm) const;
273
274 int getTTmpIdx(unsigned Val) const;
275
276 const MCInstrInfo *getMCII() const { return MCII.get(); }
277
278 bool isVI() const;
279 bool isGFX9() const;
280 bool isGFX90A() const;
281 bool isGFX9Plus() const;
282 bool isGFX10() const;
283 bool isGFX10Plus() const;
284 bool isGFX11() const;
285 bool isGFX11Plus() const;
286 bool isGFX12() const;
287 bool isGFX12Plus() const;
288
289 bool hasArchitectedFlatScratch() const;
290 bool hasKernargPreload() const;
291
292 bool isMacDPP(MCInst &MI) const;
293};
294
295//===----------------------------------------------------------------------===//
296// AMDGPUSymbolizer
297//===----------------------------------------------------------------------===//
298
299class AMDGPUSymbolizer : public MCSymbolizer {
300private:
301 void *DisInfo;
302 std::vector<uint64_t> ReferencedAddresses;
303
304public:
305 AMDGPUSymbolizer(MCContext &Ctx, std::unique_ptr<MCRelocationInfo> &&RelInfo,
306 void *disInfo)
307 : MCSymbolizer(Ctx, std::move(RelInfo)), DisInfo(disInfo) {}
308
309 bool tryAddingSymbolicOperand(MCInst &Inst, raw_ostream &cStream,
310 int64_t Value, uint64_t Address, bool IsBranch,
311 uint64_t Offset, uint64_t OpSize,
312 uint64_t InstSize) override;
313
314 void tryAddingPcLoadReferenceComment(raw_ostream &cStream,
315 int64_t Value,
316 uint64_t Address) override;
317
318 ArrayRef<uint64_t> getReferencedAddresses() const override {
319 return ReferencedAddresses;
320 }
321};
322
323} // end namespace llvm
324
325#endif // LLVM_LIB_TARGET_AMDGPU_DISASSEMBLER_AMDGPUDISASSEMBLER_H
326