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