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 27 namespace llvm { 28 29 class MCAsmInfo; 30 class MCInst; 31 class MCOperand; 32 class MCSubtargetInfo; 33 class Twine; 34 35 // Exposes an interface expected by autogenerated code in 36 // FixedLenDecoderEmitter 37 class DecoderUInt128 { 38 private: 39 uint64_t Lo = 0; 40 uint64_t Hi = 0; 41 42 public: 43 DecoderUInt128() = default; Lo(Lo)44 DecoderUInt128(uint64_t Lo, uint64_t Hi = 0) : Lo(Lo), Hi(Hi) {} 45 operator bool() const { return Lo || Hi; } insertBits(uint64_t SubBits,unsigned BitPosition,unsigned NumBits)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 } extractBitsAsZExtValue(unsigned NumBits,unsigned BitPosition)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 93 class AMDGPUDisassembler : public MCDisassembler { 94 private: 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 111 public: 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> tryDecodeInst(const uint8_t * Table,MCInst & MI,InsnType Inst,uint64_t Address,raw_ostream & Comments)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> tryDecodeInst(const uint8_t * Table1,const uint8_t * Table2,MCInst & MI,InsnType Inst,uint64_t Address,raw_ostream & Comments)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 getMCII()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 299 class AMDGPUSymbolizer : public MCSymbolizer { 300 private: 301 void *DisInfo; 302 std::vector<uint64_t> ReferencedAddresses; 303 304 public: AMDGPUSymbolizer(MCContext & Ctx,std::unique_ptr<MCRelocationInfo> && RelInfo,void * disInfo)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 getReferencedAddresses()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