12cab237bSDimitry Andric //===- AMDGPUDisassembler.cpp - Disassembler for AMDGPU ISA ---------------===//
23ca95b02SDimitry Andric //
33ca95b02SDimitry Andric // The LLVM Compiler Infrastructure
43ca95b02SDimitry Andric //
53ca95b02SDimitry Andric // This file is distributed under the University of Illinois Open Source
63ca95b02SDimitry Andric // License. See LICENSE.TXT for details.
73ca95b02SDimitry Andric //
83ca95b02SDimitry Andric //===----------------------------------------------------------------------===//
93ca95b02SDimitry Andric //
103ca95b02SDimitry Andric //===----------------------------------------------------------------------===//
113ca95b02SDimitry Andric //
123ca95b02SDimitry Andric /// \file
133ca95b02SDimitry Andric ///
143ca95b02SDimitry Andric /// This file contains definition for AMDGPU ISA disassembler
153ca95b02SDimitry Andric //
163ca95b02SDimitry Andric //===----------------------------------------------------------------------===//
173ca95b02SDimitry Andric
183ca95b02SDimitry Andric // ToDo: What to do with instruction suffixes (v_mov_b32 vs v_mov_b32_e32)?
193ca95b02SDimitry Andric
202cab237bSDimitry Andric #include "Disassembler/AMDGPUDisassembler.h"
213ca95b02SDimitry Andric #include "AMDGPU.h"
223ca95b02SDimitry Andric #include "AMDGPURegisterInfo.h"
23*4ba319b5SDimitry Andric #include "MCTargetDesc/AMDGPUMCTargetDesc.h"
243ca95b02SDimitry Andric #include "SIDefines.h"
25*4ba319b5SDimitry Andric #include "MCTargetDesc/AMDGPUMCTargetDesc.h"
263ca95b02SDimitry Andric #include "Utils/AMDGPUBaseInfo.h"
272cab237bSDimitry Andric #include "llvm-c/Disassembler.h"
282cab237bSDimitry Andric #include "llvm/ADT/APInt.h"
292cab237bSDimitry Andric #include "llvm/ADT/ArrayRef.h"
302cab237bSDimitry Andric #include "llvm/ADT/Twine.h"
31db17bf38SDimitry Andric #include "llvm/BinaryFormat/ELF.h"
323ca95b02SDimitry Andric #include "llvm/MC/MCContext.h"
332cab237bSDimitry Andric #include "llvm/MC/MCDisassembler/MCDisassembler.h"
342cab237bSDimitry Andric #include "llvm/MC/MCExpr.h"
353ca95b02SDimitry Andric #include "llvm/MC/MCFixedLenDisassembler.h"
363ca95b02SDimitry Andric #include "llvm/MC/MCInst.h"
373ca95b02SDimitry Andric #include "llvm/MC/MCSubtargetInfo.h"
38db17bf38SDimitry Andric #include "llvm/Support/Endian.h"
392cab237bSDimitry Andric #include "llvm/Support/ErrorHandling.h"
402cab237bSDimitry Andric #include "llvm/Support/MathExtras.h"
413ca95b02SDimitry Andric #include "llvm/Support/TargetRegistry.h"
422cab237bSDimitry Andric #include "llvm/Support/raw_ostream.h"
432cab237bSDimitry Andric #include <algorithm>
442cab237bSDimitry Andric #include <cassert>
452cab237bSDimitry Andric #include <cstddef>
462cab237bSDimitry Andric #include <cstdint>
472cab237bSDimitry Andric #include <iterator>
482cab237bSDimitry Andric #include <tuple>
492cab237bSDimitry Andric #include <vector>
503ca95b02SDimitry Andric
513ca95b02SDimitry Andric using namespace llvm;
523ca95b02SDimitry Andric
533ca95b02SDimitry Andric #define DEBUG_TYPE "amdgpu-disassembler"
543ca95b02SDimitry Andric
552cab237bSDimitry Andric using DecodeStatus = llvm::MCDisassembler::DecodeStatus;
563ca95b02SDimitry Andric
573ca95b02SDimitry Andric inline static MCDisassembler::DecodeStatus
addOperand(MCInst & Inst,const MCOperand & Opnd)583ca95b02SDimitry Andric addOperand(MCInst &Inst, const MCOperand& Opnd) {
593ca95b02SDimitry Andric Inst.addOperand(Opnd);
603ca95b02SDimitry Andric return Opnd.isValid() ?
613ca95b02SDimitry Andric MCDisassembler::Success :
623ca95b02SDimitry Andric MCDisassembler::SoftFail;
633ca95b02SDimitry Andric }
643ca95b02SDimitry Andric
insertNamedMCOperand(MCInst & MI,const MCOperand & Op,uint16_t NameIdx)65edd7eaddSDimitry Andric static int insertNamedMCOperand(MCInst &MI, const MCOperand &Op,
66edd7eaddSDimitry Andric uint16_t NameIdx) {
67edd7eaddSDimitry Andric int OpIdx = AMDGPU::getNamedOperandIdx(MI.getOpcode(), NameIdx);
68edd7eaddSDimitry Andric if (OpIdx != -1) {
69edd7eaddSDimitry Andric auto I = MI.begin();
70edd7eaddSDimitry Andric std::advance(I, OpIdx);
71edd7eaddSDimitry Andric MI.insert(I, Op);
72edd7eaddSDimitry Andric }
73edd7eaddSDimitry Andric return OpIdx;
74edd7eaddSDimitry Andric }
75edd7eaddSDimitry Andric
decodeSoppBrTarget(MCInst & Inst,unsigned Imm,uint64_t Addr,const void * Decoder)76d88c1a5aSDimitry Andric static DecodeStatus decodeSoppBrTarget(MCInst &Inst, unsigned Imm,
77d88c1a5aSDimitry Andric uint64_t Addr, const void *Decoder) {
78d88c1a5aSDimitry Andric auto DAsm = static_cast<const AMDGPUDisassembler*>(Decoder);
79d88c1a5aSDimitry Andric
80d88c1a5aSDimitry Andric APInt SignedOffset(18, Imm * 4, true);
81d88c1a5aSDimitry Andric int64_t Offset = (SignedOffset.sext(64) + 4 + Addr).getSExtValue();
82d88c1a5aSDimitry Andric
83d88c1a5aSDimitry Andric if (DAsm->tryAddingSymbolicOperand(Inst, Offset, Addr, true, 2, 2))
84d88c1a5aSDimitry Andric return MCDisassembler::Success;
85d88c1a5aSDimitry Andric return addOperand(Inst, MCOperand::createImm(Imm));
86d88c1a5aSDimitry Andric }
87d88c1a5aSDimitry Andric
88302affcbSDimitry Andric #define DECODE_OPERAND(StaticDecoderName, DecoderName) \
89302affcbSDimitry Andric static DecodeStatus StaticDecoderName(MCInst &Inst, \
903ca95b02SDimitry Andric unsigned Imm, \
913ca95b02SDimitry Andric uint64_t /*Addr*/, \
923ca95b02SDimitry Andric const void *Decoder) { \
933ca95b02SDimitry Andric auto DAsm = static_cast<const AMDGPUDisassembler*>(Decoder); \
94302affcbSDimitry Andric return addOperand(Inst, DAsm->DecoderName(Imm)); \
953ca95b02SDimitry Andric }
963ca95b02SDimitry Andric
97302affcbSDimitry Andric #define DECODE_OPERAND_REG(RegClass) \
98302affcbSDimitry Andric DECODE_OPERAND(Decode##RegClass##RegisterClass, decodeOperand_##RegClass)
993ca95b02SDimitry Andric
100302affcbSDimitry Andric DECODE_OPERAND_REG(VGPR_32)
DECODE_OPERAND_REG(VS_32)101302affcbSDimitry Andric DECODE_OPERAND_REG(VS_32)
102302affcbSDimitry Andric DECODE_OPERAND_REG(VS_64)
103b40b48b8SDimitry Andric DECODE_OPERAND_REG(VS_128)
1043ca95b02SDimitry Andric
105302affcbSDimitry Andric DECODE_OPERAND_REG(VReg_64)
106302affcbSDimitry Andric DECODE_OPERAND_REG(VReg_96)
107302affcbSDimitry Andric DECODE_OPERAND_REG(VReg_128)
1083ca95b02SDimitry Andric
109302affcbSDimitry Andric DECODE_OPERAND_REG(SReg_32)
110302affcbSDimitry Andric DECODE_OPERAND_REG(SReg_32_XM0_XEXEC)
1112cab237bSDimitry Andric DECODE_OPERAND_REG(SReg_32_XEXEC_HI)
112302affcbSDimitry Andric DECODE_OPERAND_REG(SReg_64)
113302affcbSDimitry Andric DECODE_OPERAND_REG(SReg_64_XEXEC)
114302affcbSDimitry Andric DECODE_OPERAND_REG(SReg_128)
115302affcbSDimitry Andric DECODE_OPERAND_REG(SReg_256)
116302affcbSDimitry Andric DECODE_OPERAND_REG(SReg_512)
1173ca95b02SDimitry Andric
118d88c1a5aSDimitry Andric static DecodeStatus decodeOperand_VSrc16(MCInst &Inst,
119d88c1a5aSDimitry Andric unsigned Imm,
120d88c1a5aSDimitry Andric uint64_t Addr,
121d88c1a5aSDimitry Andric const void *Decoder) {
122d88c1a5aSDimitry Andric auto DAsm = static_cast<const AMDGPUDisassembler*>(Decoder);
123d88c1a5aSDimitry Andric return addOperand(Inst, DAsm->decodeOperand_VSrc16(Imm));
124d88c1a5aSDimitry Andric }
125d88c1a5aSDimitry Andric
decodeOperand_VSrcV216(MCInst & Inst,unsigned Imm,uint64_t Addr,const void * Decoder)1267a7e6055SDimitry Andric static DecodeStatus decodeOperand_VSrcV216(MCInst &Inst,
1277a7e6055SDimitry Andric unsigned Imm,
1287a7e6055SDimitry Andric uint64_t Addr,
1297a7e6055SDimitry Andric const void *Decoder) {
1307a7e6055SDimitry Andric auto DAsm = static_cast<const AMDGPUDisassembler*>(Decoder);
1317a7e6055SDimitry Andric return addOperand(Inst, DAsm->decodeOperand_VSrcV216(Imm));
1327a7e6055SDimitry Andric }
1333ca95b02SDimitry Andric
134edd7eaddSDimitry Andric #define DECODE_SDWA(DecName) \
135edd7eaddSDimitry Andric DECODE_OPERAND(decodeSDWA##DecName, decodeSDWA##DecName)
136302affcbSDimitry Andric
137edd7eaddSDimitry Andric DECODE_SDWA(Src32)
DECODE_SDWA(Src16)138edd7eaddSDimitry Andric DECODE_SDWA(Src16)
139edd7eaddSDimitry Andric DECODE_SDWA(VopcDst)
140302affcbSDimitry Andric
1413ca95b02SDimitry Andric #include "AMDGPUGenDisassemblerTables.inc"
1423ca95b02SDimitry Andric
1433ca95b02SDimitry Andric //===----------------------------------------------------------------------===//
1443ca95b02SDimitry Andric //
1453ca95b02SDimitry Andric //===----------------------------------------------------------------------===//
1463ca95b02SDimitry Andric
1473ca95b02SDimitry Andric template <typename T> static inline T eatBytes(ArrayRef<uint8_t>& Bytes) {
1483ca95b02SDimitry Andric assert(Bytes.size() >= sizeof(T));
1493ca95b02SDimitry Andric const auto Res = support::endian::read<T, support::endianness::little>(Bytes.data());
1503ca95b02SDimitry Andric Bytes = Bytes.slice(sizeof(T));
1513ca95b02SDimitry Andric return Res;
1523ca95b02SDimitry Andric }
1533ca95b02SDimitry Andric
tryDecodeInst(const uint8_t * Table,MCInst & MI,uint64_t Inst,uint64_t Address) const1543ca95b02SDimitry Andric DecodeStatus AMDGPUDisassembler::tryDecodeInst(const uint8_t* Table,
1553ca95b02SDimitry Andric MCInst &MI,
1563ca95b02SDimitry Andric uint64_t Inst,
1573ca95b02SDimitry Andric uint64_t Address) const {
1583ca95b02SDimitry Andric assert(MI.getOpcode() == 0);
1593ca95b02SDimitry Andric assert(MI.getNumOperands() == 0);
1603ca95b02SDimitry Andric MCInst TmpInst;
161d8866befSDimitry Andric HasLiteral = false;
1623ca95b02SDimitry Andric const auto SavedBytes = Bytes;
1633ca95b02SDimitry Andric if (decodeInstruction(Table, TmpInst, Inst, Address, this, STI)) {
1643ca95b02SDimitry Andric MI = TmpInst;
1653ca95b02SDimitry Andric return MCDisassembler::Success;
1663ca95b02SDimitry Andric }
1673ca95b02SDimitry Andric Bytes = SavedBytes;
1683ca95b02SDimitry Andric return MCDisassembler::Fail;
1693ca95b02SDimitry Andric }
1703ca95b02SDimitry Andric
getInstruction(MCInst & MI,uint64_t & Size,ArrayRef<uint8_t> Bytes_,uint64_t Address,raw_ostream & WS,raw_ostream & CS) const1713ca95b02SDimitry Andric DecodeStatus AMDGPUDisassembler::getInstruction(MCInst &MI, uint64_t &Size,
1723ca95b02SDimitry Andric ArrayRef<uint8_t> Bytes_,
1733ca95b02SDimitry Andric uint64_t Address,
1743ca95b02SDimitry Andric raw_ostream &WS,
1753ca95b02SDimitry Andric raw_ostream &CS) const {
1763ca95b02SDimitry Andric CommentStream = &CS;
177edd7eaddSDimitry Andric bool IsSDWA = false;
1783ca95b02SDimitry Andric
1793ca95b02SDimitry Andric // ToDo: AMDGPUDisassembler supports only VI ISA.
1807a7e6055SDimitry Andric if (!STI.getFeatureBits()[AMDGPU::FeatureGCN3Encoding])
1817a7e6055SDimitry Andric report_fatal_error("Disassembly not yet supported for subtarget");
1823ca95b02SDimitry Andric
1833ca95b02SDimitry Andric const unsigned MaxInstBytesNum = (std::min)((size_t)8, Bytes_.size());
1843ca95b02SDimitry Andric Bytes = Bytes_.slice(0, MaxInstBytesNum);
1853ca95b02SDimitry Andric
1863ca95b02SDimitry Andric DecodeStatus Res = MCDisassembler::Fail;
1873ca95b02SDimitry Andric do {
1883ca95b02SDimitry Andric // ToDo: better to switch encoding length using some bit predicate
1893ca95b02SDimitry Andric // but it is unknown yet, so try all we can
1903ca95b02SDimitry Andric
1913ca95b02SDimitry Andric // Try to decode DPP and SDWA first to solve conflict with VOP1 and VOP2
1923ca95b02SDimitry Andric // encodings
1933ca95b02SDimitry Andric if (Bytes.size() >= 8) {
1943ca95b02SDimitry Andric const uint64_t QW = eatBytes<uint64_t>(Bytes);
1953ca95b02SDimitry Andric Res = tryDecodeInst(DecoderTableDPP64, MI, QW, Address);
1963ca95b02SDimitry Andric if (Res) break;
1973ca95b02SDimitry Andric
1983ca95b02SDimitry Andric Res = tryDecodeInst(DecoderTableSDWA64, MI, QW, Address);
199edd7eaddSDimitry Andric if (Res) { IsSDWA = true; break; }
200302affcbSDimitry Andric
201302affcbSDimitry Andric Res = tryDecodeInst(DecoderTableSDWA964, MI, QW, Address);
202edd7eaddSDimitry Andric if (Res) { IsSDWA = true; break; }
203*4ba319b5SDimitry Andric
204*4ba319b5SDimitry Andric if (STI.getFeatureBits()[AMDGPU::FeatureUnpackedD16VMem]) {
205*4ba319b5SDimitry Andric Res = tryDecodeInst(DecoderTableGFX80_UNPACKED64, MI, QW, Address);
206*4ba319b5SDimitry Andric if (Res)
207*4ba319b5SDimitry Andric break;
208*4ba319b5SDimitry Andric }
209*4ba319b5SDimitry Andric
210*4ba319b5SDimitry Andric // Some GFX9 subtargets repurposed the v_mad_mix_f32, v_mad_mixlo_f16 and
211*4ba319b5SDimitry Andric // v_mad_mixhi_f16 for FMA variants. Try to decode using this special
212*4ba319b5SDimitry Andric // table first so we print the correct name.
213*4ba319b5SDimitry Andric if (STI.getFeatureBits()[AMDGPU::FeatureFmaMixInsts]) {
214*4ba319b5SDimitry Andric Res = tryDecodeInst(DecoderTableGFX9_DL64, MI, QW, Address);
215*4ba319b5SDimitry Andric if (Res)
216*4ba319b5SDimitry Andric break;
217*4ba319b5SDimitry Andric }
2183ca95b02SDimitry Andric }
2193ca95b02SDimitry Andric
2203ca95b02SDimitry Andric // Reinitialize Bytes as DPP64 could have eaten too much
2213ca95b02SDimitry Andric Bytes = Bytes_.slice(0, MaxInstBytesNum);
2223ca95b02SDimitry Andric
2233ca95b02SDimitry Andric // Try decode 32-bit instruction
2243ca95b02SDimitry Andric if (Bytes.size() < 4) break;
2253ca95b02SDimitry Andric const uint32_t DW = eatBytes<uint32_t>(Bytes);
2263ca95b02SDimitry Andric Res = tryDecodeInst(DecoderTableVI32, MI, DW, Address);
2273ca95b02SDimitry Andric if (Res) break;
2283ca95b02SDimitry Andric
2293ca95b02SDimitry Andric Res = tryDecodeInst(DecoderTableAMDGPU32, MI, DW, Address);
2303ca95b02SDimitry Andric if (Res) break;
2313ca95b02SDimitry Andric
2322cab237bSDimitry Andric Res = tryDecodeInst(DecoderTableGFX932, MI, DW, Address);
2332cab237bSDimitry Andric if (Res) break;
2342cab237bSDimitry Andric
2353ca95b02SDimitry Andric if (Bytes.size() < 4) break;
2363ca95b02SDimitry Andric const uint64_t QW = ((uint64_t)eatBytes<uint32_t>(Bytes) << 32) | DW;
2373ca95b02SDimitry Andric Res = tryDecodeInst(DecoderTableVI64, MI, QW, Address);
2383ca95b02SDimitry Andric if (Res) break;
2393ca95b02SDimitry Andric
2403ca95b02SDimitry Andric Res = tryDecodeInst(DecoderTableAMDGPU64, MI, QW, Address);
2412cab237bSDimitry Andric if (Res) break;
2422cab237bSDimitry Andric
2432cab237bSDimitry Andric Res = tryDecodeInst(DecoderTableGFX964, MI, QW, Address);
2443ca95b02SDimitry Andric } while (false);
2453ca95b02SDimitry Andric
2467a7e6055SDimitry Andric if (Res && (MI.getOpcode() == AMDGPU::V_MAC_F32_e64_vi ||
2477a7e6055SDimitry Andric MI.getOpcode() == AMDGPU::V_MAC_F32_e64_si ||
248*4ba319b5SDimitry Andric MI.getOpcode() == AMDGPU::V_MAC_F16_e64_vi ||
249*4ba319b5SDimitry Andric MI.getOpcode() == AMDGPU::V_FMAC_F32_e64_vi)) {
2507a7e6055SDimitry Andric // Insert dummy unused src2_modifiers.
251edd7eaddSDimitry Andric insertNamedMCOperand(MI, MCOperand::createImm(0),
2527a7e6055SDimitry Andric AMDGPU::OpName::src2_modifiers);
2537a7e6055SDimitry Andric }
2547a7e6055SDimitry Andric
2552cab237bSDimitry Andric if (Res && (MCII->get(MI.getOpcode()).TSFlags & SIInstrFlags::MIMG)) {
2562cab237bSDimitry Andric Res = convertMIMGInst(MI);
2572cab237bSDimitry Andric }
2582cab237bSDimitry Andric
259edd7eaddSDimitry Andric if (Res && IsSDWA)
260edd7eaddSDimitry Andric Res = convertSDWAInst(MI);
261edd7eaddSDimitry Andric
262*4ba319b5SDimitry Andric // if the opcode was not recognized we'll assume a Size of 4 bytes
263*4ba319b5SDimitry Andric // (unless there are fewer bytes left)
264*4ba319b5SDimitry Andric Size = Res ? (MaxInstBytesNum - Bytes.size())
265*4ba319b5SDimitry Andric : std::min((size_t)4, Bytes_.size());
2663ca95b02SDimitry Andric return Res;
2673ca95b02SDimitry Andric }
2683ca95b02SDimitry Andric
convertSDWAInst(MCInst & MI) const269edd7eaddSDimitry Andric DecodeStatus AMDGPUDisassembler::convertSDWAInst(MCInst &MI) const {
270edd7eaddSDimitry Andric if (STI.getFeatureBits()[AMDGPU::FeatureGFX9]) {
271edd7eaddSDimitry Andric if (AMDGPU::getNamedOperandIdx(MI.getOpcode(), AMDGPU::OpName::sdst) != -1)
272edd7eaddSDimitry Andric // VOPC - insert clamp
273edd7eaddSDimitry Andric insertNamedMCOperand(MI, MCOperand::createImm(0), AMDGPU::OpName::clamp);
274edd7eaddSDimitry Andric } else if (STI.getFeatureBits()[AMDGPU::FeatureVolcanicIslands]) {
275edd7eaddSDimitry Andric int SDst = AMDGPU::getNamedOperandIdx(MI.getOpcode(), AMDGPU::OpName::sdst);
276edd7eaddSDimitry Andric if (SDst != -1) {
277edd7eaddSDimitry Andric // VOPC - insert VCC register as sdst
2782cab237bSDimitry Andric insertNamedMCOperand(MI, createRegOperand(AMDGPU::VCC),
279edd7eaddSDimitry Andric AMDGPU::OpName::sdst);
280edd7eaddSDimitry Andric } else {
281edd7eaddSDimitry Andric // VOP1/2 - insert omod if present in instruction
282edd7eaddSDimitry Andric insertNamedMCOperand(MI, MCOperand::createImm(0), AMDGPU::OpName::omod);
283edd7eaddSDimitry Andric }
284edd7eaddSDimitry Andric }
285edd7eaddSDimitry Andric return MCDisassembler::Success;
286edd7eaddSDimitry Andric }
287edd7eaddSDimitry Andric
288*4ba319b5SDimitry Andric // Note that MIMG format provides no information about VADDR size.
289*4ba319b5SDimitry Andric // Consequently, decoded instructions always show address
290*4ba319b5SDimitry Andric // as if it has 1 dword, which could be not really so.
convertMIMGInst(MCInst & MI) const2912cab237bSDimitry Andric DecodeStatus AMDGPUDisassembler::convertMIMGInst(MCInst &MI) const {
292*4ba319b5SDimitry Andric
293*4ba319b5SDimitry Andric int VDstIdx = AMDGPU::getNamedOperandIdx(MI.getOpcode(),
294*4ba319b5SDimitry Andric AMDGPU::OpName::vdst);
295*4ba319b5SDimitry Andric
2962cab237bSDimitry Andric int VDataIdx = AMDGPU::getNamedOperandIdx(MI.getOpcode(),
2972cab237bSDimitry Andric AMDGPU::OpName::vdata);
2982cab237bSDimitry Andric
2992cab237bSDimitry Andric int DMaskIdx = AMDGPU::getNamedOperandIdx(MI.getOpcode(),
3002cab237bSDimitry Andric AMDGPU::OpName::dmask);
301*4ba319b5SDimitry Andric
302*4ba319b5SDimitry Andric int TFEIdx = AMDGPU::getNamedOperandIdx(MI.getOpcode(),
303*4ba319b5SDimitry Andric AMDGPU::OpName::tfe);
304*4ba319b5SDimitry Andric int D16Idx = AMDGPU::getNamedOperandIdx(MI.getOpcode(),
305*4ba319b5SDimitry Andric AMDGPU::OpName::d16);
306*4ba319b5SDimitry Andric
307*4ba319b5SDimitry Andric assert(VDataIdx != -1);
308*4ba319b5SDimitry Andric assert(DMaskIdx != -1);
309*4ba319b5SDimitry Andric assert(TFEIdx != -1);
310*4ba319b5SDimitry Andric
311*4ba319b5SDimitry Andric bool IsAtomic = (VDstIdx != -1);
312*4ba319b5SDimitry Andric bool IsGather4 = MCII->get(MI.getOpcode()).TSFlags & SIInstrFlags::Gather4;
313*4ba319b5SDimitry Andric
3142cab237bSDimitry Andric unsigned DMask = MI.getOperand(DMaskIdx).getImm() & 0xf;
3152cab237bSDimitry Andric if (DMask == 0)
3162cab237bSDimitry Andric return MCDisassembler::Success;
3172cab237bSDimitry Andric
318*4ba319b5SDimitry Andric unsigned DstSize = IsGather4 ? 4 : countPopulation(DMask);
319*4ba319b5SDimitry Andric if (DstSize == 1)
3202cab237bSDimitry Andric return MCDisassembler::Success;
3212cab237bSDimitry Andric
322*4ba319b5SDimitry Andric bool D16 = D16Idx >= 0 && MI.getOperand(D16Idx).getImm();
323*4ba319b5SDimitry Andric if (D16 && AMDGPU::hasPackedD16(STI)) {
324*4ba319b5SDimitry Andric DstSize = (DstSize + 1) / 2;
325*4ba319b5SDimitry Andric }
326*4ba319b5SDimitry Andric
327*4ba319b5SDimitry Andric // FIXME: Add tfe support
328*4ba319b5SDimitry Andric if (MI.getOperand(TFEIdx).getImm())
329*4ba319b5SDimitry Andric return MCDisassembler::Success;
330*4ba319b5SDimitry Andric
331*4ba319b5SDimitry Andric int NewOpcode = -1;
332*4ba319b5SDimitry Andric
333*4ba319b5SDimitry Andric if (IsGather4) {
334*4ba319b5SDimitry Andric if (D16 && AMDGPU::hasPackedD16(STI))
335*4ba319b5SDimitry Andric NewOpcode = AMDGPU::getMaskedMIMGOp(MI.getOpcode(), 2);
336*4ba319b5SDimitry Andric else
337*4ba319b5SDimitry Andric return MCDisassembler::Success;
338*4ba319b5SDimitry Andric } else {
339*4ba319b5SDimitry Andric NewOpcode = AMDGPU::getMaskedMIMGOp(MI.getOpcode(), DstSize);
340*4ba319b5SDimitry Andric if (NewOpcode == -1)
341*4ba319b5SDimitry Andric return MCDisassembler::Success;
342*4ba319b5SDimitry Andric }
343*4ba319b5SDimitry Andric
3442cab237bSDimitry Andric auto RCID = MCII->get(NewOpcode).OpInfo[VDataIdx].RegClass;
3452cab237bSDimitry Andric
346*4ba319b5SDimitry Andric // Get first subregister of VData
3472cab237bSDimitry Andric unsigned Vdata0 = MI.getOperand(VDataIdx).getReg();
348*4ba319b5SDimitry Andric unsigned VdataSub0 = MRI.getSubReg(Vdata0, AMDGPU::sub0);
349*4ba319b5SDimitry Andric Vdata0 = (VdataSub0 != 0)? VdataSub0 : Vdata0;
350*4ba319b5SDimitry Andric
351*4ba319b5SDimitry Andric // Widen the register to the correct number of enabled channels.
3522cab237bSDimitry Andric auto NewVdata = MRI.getMatchingSuperReg(Vdata0, AMDGPU::sub0,
3532cab237bSDimitry Andric &MRI.getRegClass(RCID));
3542cab237bSDimitry Andric if (NewVdata == AMDGPU::NoRegister) {
3552cab237bSDimitry Andric // It's possible to encode this such that the low register + enabled
3562cab237bSDimitry Andric // components exceeds the register count.
3572cab237bSDimitry Andric return MCDisassembler::Success;
3582cab237bSDimitry Andric }
3592cab237bSDimitry Andric
3602cab237bSDimitry Andric MI.setOpcode(NewOpcode);
3612cab237bSDimitry Andric // vaddr will be always appear as a single VGPR. This will look different than
3622cab237bSDimitry Andric // how it is usually emitted because the number of register components is not
3632cab237bSDimitry Andric // in the instruction encoding.
3642cab237bSDimitry Andric MI.getOperand(VDataIdx) = MCOperand::createReg(NewVdata);
365*4ba319b5SDimitry Andric
366*4ba319b5SDimitry Andric if (IsAtomic) {
367*4ba319b5SDimitry Andric // Atomic operations have an additional operand (a copy of data)
368*4ba319b5SDimitry Andric MI.getOperand(VDstIdx) = MCOperand::createReg(NewVdata);
369*4ba319b5SDimitry Andric }
370*4ba319b5SDimitry Andric
3712cab237bSDimitry Andric return MCDisassembler::Success;
3722cab237bSDimitry Andric }
3732cab237bSDimitry Andric
getRegClassName(unsigned RegClassID) const3743ca95b02SDimitry Andric const char* AMDGPUDisassembler::getRegClassName(unsigned RegClassID) const {
3753ca95b02SDimitry Andric return getContext().getRegisterInfo()->
3763ca95b02SDimitry Andric getRegClassName(&AMDGPUMCRegisterClasses[RegClassID]);
3773ca95b02SDimitry Andric }
3783ca95b02SDimitry Andric
3793ca95b02SDimitry Andric inline
errOperand(unsigned V,const Twine & ErrMsg) const3803ca95b02SDimitry Andric MCOperand AMDGPUDisassembler::errOperand(unsigned V,
3813ca95b02SDimitry Andric const Twine& ErrMsg) const {
3823ca95b02SDimitry Andric *CommentStream << "Error: " + ErrMsg;
3833ca95b02SDimitry Andric
3843ca95b02SDimitry Andric // ToDo: add support for error operands to MCInst.h
3853ca95b02SDimitry Andric // return MCOperand::createError(V);
3863ca95b02SDimitry Andric return MCOperand();
3873ca95b02SDimitry Andric }
3883ca95b02SDimitry Andric
3893ca95b02SDimitry Andric inline
createRegOperand(unsigned int RegId) const3903ca95b02SDimitry Andric MCOperand AMDGPUDisassembler::createRegOperand(unsigned int RegId) const {
3912cab237bSDimitry Andric return MCOperand::createReg(AMDGPU::getMCReg(RegId, STI));
3923ca95b02SDimitry Andric }
3933ca95b02SDimitry Andric
3943ca95b02SDimitry Andric inline
createRegOperand(unsigned RegClassID,unsigned Val) const3953ca95b02SDimitry Andric MCOperand AMDGPUDisassembler::createRegOperand(unsigned RegClassID,
3963ca95b02SDimitry Andric unsigned Val) const {
3973ca95b02SDimitry Andric const auto& RegCl = AMDGPUMCRegisterClasses[RegClassID];
3983ca95b02SDimitry Andric if (Val >= RegCl.getNumRegs())
3993ca95b02SDimitry Andric return errOperand(Val, Twine(getRegClassName(RegClassID)) +
4003ca95b02SDimitry Andric ": unknown register " + Twine(Val));
4013ca95b02SDimitry Andric return createRegOperand(RegCl.getRegister(Val));
4023ca95b02SDimitry Andric }
4033ca95b02SDimitry Andric
4043ca95b02SDimitry Andric inline
createSRegOperand(unsigned SRegClassID,unsigned Val) const4053ca95b02SDimitry Andric MCOperand AMDGPUDisassembler::createSRegOperand(unsigned SRegClassID,
4063ca95b02SDimitry Andric unsigned Val) const {
4073ca95b02SDimitry Andric // ToDo: SI/CI have 104 SGPRs, VI - 102
4083ca95b02SDimitry Andric // Valery: here we accepting as much as we can, let assembler sort it out
4093ca95b02SDimitry Andric int shift = 0;
4103ca95b02SDimitry Andric switch (SRegClassID) {
4113ca95b02SDimitry Andric case AMDGPU::SGPR_32RegClassID:
4123ca95b02SDimitry Andric case AMDGPU::TTMP_32RegClassID:
4133ca95b02SDimitry Andric break;
4143ca95b02SDimitry Andric case AMDGPU::SGPR_64RegClassID:
4153ca95b02SDimitry Andric case AMDGPU::TTMP_64RegClassID:
4163ca95b02SDimitry Andric shift = 1;
4173ca95b02SDimitry Andric break;
4183ca95b02SDimitry Andric case AMDGPU::SGPR_128RegClassID:
4193ca95b02SDimitry Andric case AMDGPU::TTMP_128RegClassID:
4203ca95b02SDimitry Andric // ToDo: unclear if s[100:104] is available on VI. Can we use VCC as SGPR in
4213ca95b02SDimitry Andric // this bundle?
422da09e106SDimitry Andric case AMDGPU::SGPR_256RegClassID:
423da09e106SDimitry Andric case AMDGPU::TTMP_256RegClassID:
4243ca95b02SDimitry Andric // ToDo: unclear if s[96:104] is available on VI. Can we use VCC as SGPR in
4253ca95b02SDimitry Andric // this bundle?
426da09e106SDimitry Andric case AMDGPU::SGPR_512RegClassID:
427da09e106SDimitry Andric case AMDGPU::TTMP_512RegClassID:
4283ca95b02SDimitry Andric shift = 2;
4293ca95b02SDimitry Andric break;
4303ca95b02SDimitry Andric // ToDo: unclear if s[88:104] is available on VI. Can we use VCC as SGPR in
4313ca95b02SDimitry Andric // this bundle?
4323ca95b02SDimitry Andric default:
433d88c1a5aSDimitry Andric llvm_unreachable("unhandled register class");
4343ca95b02SDimitry Andric }
435d88c1a5aSDimitry Andric
436d88c1a5aSDimitry Andric if (Val % (1 << shift)) {
4373ca95b02SDimitry Andric *CommentStream << "Warning: " << getRegClassName(SRegClassID)
4383ca95b02SDimitry Andric << ": scalar reg isn't aligned " << Val;
439d88c1a5aSDimitry Andric }
440d88c1a5aSDimitry Andric
4413ca95b02SDimitry Andric return createRegOperand(SRegClassID, Val >> shift);
4423ca95b02SDimitry Andric }
4433ca95b02SDimitry Andric
decodeOperand_VS_32(unsigned Val) const4443ca95b02SDimitry Andric MCOperand AMDGPUDisassembler::decodeOperand_VS_32(unsigned Val) const {
4453ca95b02SDimitry Andric return decodeSrcOp(OPW32, Val);
4463ca95b02SDimitry Andric }
4473ca95b02SDimitry Andric
decodeOperand_VS_64(unsigned Val) const4483ca95b02SDimitry Andric MCOperand AMDGPUDisassembler::decodeOperand_VS_64(unsigned Val) const {
4493ca95b02SDimitry Andric return decodeSrcOp(OPW64, Val);
4503ca95b02SDimitry Andric }
4513ca95b02SDimitry Andric
decodeOperand_VS_128(unsigned Val) const452b40b48b8SDimitry Andric MCOperand AMDGPUDisassembler::decodeOperand_VS_128(unsigned Val) const {
453b40b48b8SDimitry Andric return decodeSrcOp(OPW128, Val);
454b40b48b8SDimitry Andric }
455b40b48b8SDimitry Andric
decodeOperand_VSrc16(unsigned Val) const456d88c1a5aSDimitry Andric MCOperand AMDGPUDisassembler::decodeOperand_VSrc16(unsigned Val) const {
457d88c1a5aSDimitry Andric return decodeSrcOp(OPW16, Val);
458d88c1a5aSDimitry Andric }
459d88c1a5aSDimitry Andric
decodeOperand_VSrcV216(unsigned Val) const4607a7e6055SDimitry Andric MCOperand AMDGPUDisassembler::decodeOperand_VSrcV216(unsigned Val) const {
4617a7e6055SDimitry Andric return decodeSrcOp(OPWV216, Val);
4627a7e6055SDimitry Andric }
4637a7e6055SDimitry Andric
decodeOperand_VGPR_32(unsigned Val) const4643ca95b02SDimitry Andric MCOperand AMDGPUDisassembler::decodeOperand_VGPR_32(unsigned Val) const {
465d88c1a5aSDimitry Andric // Some instructions have operand restrictions beyond what the encoding
466d88c1a5aSDimitry Andric // allows. Some ordinarily VSrc_32 operands are VGPR_32, so clear the extra
467d88c1a5aSDimitry Andric // high bit.
468d88c1a5aSDimitry Andric Val &= 255;
469d88c1a5aSDimitry Andric
4703ca95b02SDimitry Andric return createRegOperand(AMDGPU::VGPR_32RegClassID, Val);
4713ca95b02SDimitry Andric }
4723ca95b02SDimitry Andric
decodeOperand_VReg_64(unsigned Val) const4733ca95b02SDimitry Andric MCOperand AMDGPUDisassembler::decodeOperand_VReg_64(unsigned Val) const {
4743ca95b02SDimitry Andric return createRegOperand(AMDGPU::VReg_64RegClassID, Val);
4753ca95b02SDimitry Andric }
4763ca95b02SDimitry Andric
decodeOperand_VReg_96(unsigned Val) const4773ca95b02SDimitry Andric MCOperand AMDGPUDisassembler::decodeOperand_VReg_96(unsigned Val) const {
4783ca95b02SDimitry Andric return createRegOperand(AMDGPU::VReg_96RegClassID, Val);
4793ca95b02SDimitry Andric }
4803ca95b02SDimitry Andric
decodeOperand_VReg_128(unsigned Val) const4813ca95b02SDimitry Andric MCOperand AMDGPUDisassembler::decodeOperand_VReg_128(unsigned Val) const {
4823ca95b02SDimitry Andric return createRegOperand(AMDGPU::VReg_128RegClassID, Val);
4833ca95b02SDimitry Andric }
4843ca95b02SDimitry Andric
decodeOperand_SReg_32(unsigned Val) const4853ca95b02SDimitry Andric MCOperand AMDGPUDisassembler::decodeOperand_SReg_32(unsigned Val) const {
4863ca95b02SDimitry Andric // table-gen generated disassembler doesn't care about operand types
4873ca95b02SDimitry Andric // leaving only registry class so SSrc_32 operand turns into SReg_32
4883ca95b02SDimitry Andric // and therefore we accept immediates and literals here as well
4893ca95b02SDimitry Andric return decodeSrcOp(OPW32, Val);
4903ca95b02SDimitry Andric }
4913ca95b02SDimitry Andric
decodeOperand_SReg_32_XM0_XEXEC(unsigned Val) const492d88c1a5aSDimitry Andric MCOperand AMDGPUDisassembler::decodeOperand_SReg_32_XM0_XEXEC(
493d88c1a5aSDimitry Andric unsigned Val) const {
494d88c1a5aSDimitry Andric // SReg_32_XM0 is SReg_32 without M0 or EXEC_LO/EXEC_HI
4953ca95b02SDimitry Andric return decodeOperand_SReg_32(Val);
4963ca95b02SDimitry Andric }
4973ca95b02SDimitry Andric
decodeOperand_SReg_32_XEXEC_HI(unsigned Val) const4982cab237bSDimitry Andric MCOperand AMDGPUDisassembler::decodeOperand_SReg_32_XEXEC_HI(
4992cab237bSDimitry Andric unsigned Val) const {
5002cab237bSDimitry Andric // SReg_32_XM0 is SReg_32 without EXEC_HI
5012cab237bSDimitry Andric return decodeOperand_SReg_32(Val);
5022cab237bSDimitry Andric }
5032cab237bSDimitry Andric
decodeOperand_SReg_64(unsigned Val) const5043ca95b02SDimitry Andric MCOperand AMDGPUDisassembler::decodeOperand_SReg_64(unsigned Val) const {
505d88c1a5aSDimitry Andric return decodeSrcOp(OPW64, Val);
506d88c1a5aSDimitry Andric }
507d88c1a5aSDimitry Andric
decodeOperand_SReg_64_XEXEC(unsigned Val) const508d88c1a5aSDimitry Andric MCOperand AMDGPUDisassembler::decodeOperand_SReg_64_XEXEC(unsigned Val) const {
5093ca95b02SDimitry Andric return decodeSrcOp(OPW64, Val);
5103ca95b02SDimitry Andric }
5113ca95b02SDimitry Andric
decodeOperand_SReg_128(unsigned Val) const5123ca95b02SDimitry Andric MCOperand AMDGPUDisassembler::decodeOperand_SReg_128(unsigned Val) const {
5133ca95b02SDimitry Andric return decodeSrcOp(OPW128, Val);
5143ca95b02SDimitry Andric }
5153ca95b02SDimitry Andric
decodeOperand_SReg_256(unsigned Val) const5163ca95b02SDimitry Andric MCOperand AMDGPUDisassembler::decodeOperand_SReg_256(unsigned Val) const {
517da09e106SDimitry Andric return decodeDstOp(OPW256, Val);
5183ca95b02SDimitry Andric }
5193ca95b02SDimitry Andric
decodeOperand_SReg_512(unsigned Val) const5203ca95b02SDimitry Andric MCOperand AMDGPUDisassembler::decodeOperand_SReg_512(unsigned Val) const {
521da09e106SDimitry Andric return decodeDstOp(OPW512, Val);
5223ca95b02SDimitry Andric }
5233ca95b02SDimitry Andric
decodeLiteralConstant() const5243ca95b02SDimitry Andric MCOperand AMDGPUDisassembler::decodeLiteralConstant() const {
5253ca95b02SDimitry Andric // For now all literal constants are supposed to be unsigned integer
5263ca95b02SDimitry Andric // ToDo: deal with signed/unsigned 64-bit integer constants
5273ca95b02SDimitry Andric // ToDo: deal with float/double constants
528d8866befSDimitry Andric if (!HasLiteral) {
529d8866befSDimitry Andric if (Bytes.size() < 4) {
5303ca95b02SDimitry Andric return errOperand(0, "cannot read literal, inst bytes left " +
5313ca95b02SDimitry Andric Twine(Bytes.size()));
532d8866befSDimitry Andric }
533d8866befSDimitry Andric HasLiteral = true;
534d8866befSDimitry Andric Literal = eatBytes<uint32_t>(Bytes);
535d8866befSDimitry Andric }
536d8866befSDimitry Andric return MCOperand::createImm(Literal);
5373ca95b02SDimitry Andric }
5383ca95b02SDimitry Andric
decodeIntImmed(unsigned Imm)5393ca95b02SDimitry Andric MCOperand AMDGPUDisassembler::decodeIntImmed(unsigned Imm) {
5403ca95b02SDimitry Andric using namespace AMDGPU::EncValues;
5412cab237bSDimitry Andric
5423ca95b02SDimitry Andric assert(Imm >= INLINE_INTEGER_C_MIN && Imm <= INLINE_INTEGER_C_MAX);
5433ca95b02SDimitry Andric return MCOperand::createImm((Imm <= INLINE_INTEGER_C_POSITIVE_MAX) ?
5443ca95b02SDimitry Andric (static_cast<int64_t>(Imm) - INLINE_INTEGER_C_MIN) :
5453ca95b02SDimitry Andric (INLINE_INTEGER_C_POSITIVE_MAX - static_cast<int64_t>(Imm)));
5463ca95b02SDimitry Andric // Cast prevents negative overflow.
5473ca95b02SDimitry Andric }
5483ca95b02SDimitry Andric
getInlineImmVal32(unsigned Imm)549d88c1a5aSDimitry Andric static int64_t getInlineImmVal32(unsigned Imm) {
550d88c1a5aSDimitry Andric switch (Imm) {
551d88c1a5aSDimitry Andric case 240:
552d88c1a5aSDimitry Andric return FloatToBits(0.5f);
553d88c1a5aSDimitry Andric case 241:
554d88c1a5aSDimitry Andric return FloatToBits(-0.5f);
555d88c1a5aSDimitry Andric case 242:
556d88c1a5aSDimitry Andric return FloatToBits(1.0f);
557d88c1a5aSDimitry Andric case 243:
558d88c1a5aSDimitry Andric return FloatToBits(-1.0f);
559d88c1a5aSDimitry Andric case 244:
560d88c1a5aSDimitry Andric return FloatToBits(2.0f);
561d88c1a5aSDimitry Andric case 245:
562d88c1a5aSDimitry Andric return FloatToBits(-2.0f);
563d88c1a5aSDimitry Andric case 246:
564d88c1a5aSDimitry Andric return FloatToBits(4.0f);
565d88c1a5aSDimitry Andric case 247:
566d88c1a5aSDimitry Andric return FloatToBits(-4.0f);
567d88c1a5aSDimitry Andric case 248: // 1 / (2 * PI)
568d88c1a5aSDimitry Andric return 0x3e22f983;
569d88c1a5aSDimitry Andric default:
570d88c1a5aSDimitry Andric llvm_unreachable("invalid fp inline imm");
571d88c1a5aSDimitry Andric }
572d88c1a5aSDimitry Andric }
573d88c1a5aSDimitry Andric
getInlineImmVal64(unsigned Imm)574d88c1a5aSDimitry Andric static int64_t getInlineImmVal64(unsigned Imm) {
575d88c1a5aSDimitry Andric switch (Imm) {
576d88c1a5aSDimitry Andric case 240:
577d88c1a5aSDimitry Andric return DoubleToBits(0.5);
578d88c1a5aSDimitry Andric case 241:
579d88c1a5aSDimitry Andric return DoubleToBits(-0.5);
580d88c1a5aSDimitry Andric case 242:
581d88c1a5aSDimitry Andric return DoubleToBits(1.0);
582d88c1a5aSDimitry Andric case 243:
583d88c1a5aSDimitry Andric return DoubleToBits(-1.0);
584d88c1a5aSDimitry Andric case 244:
585d88c1a5aSDimitry Andric return DoubleToBits(2.0);
586d88c1a5aSDimitry Andric case 245:
587d88c1a5aSDimitry Andric return DoubleToBits(-2.0);
588d88c1a5aSDimitry Andric case 246:
589d88c1a5aSDimitry Andric return DoubleToBits(4.0);
590d88c1a5aSDimitry Andric case 247:
591d88c1a5aSDimitry Andric return DoubleToBits(-4.0);
592d88c1a5aSDimitry Andric case 248: // 1 / (2 * PI)
593d88c1a5aSDimitry Andric return 0x3fc45f306dc9c882;
594d88c1a5aSDimitry Andric default:
595d88c1a5aSDimitry Andric llvm_unreachable("invalid fp inline imm");
596d88c1a5aSDimitry Andric }
597d88c1a5aSDimitry Andric }
598d88c1a5aSDimitry Andric
getInlineImmVal16(unsigned Imm)599d88c1a5aSDimitry Andric static int64_t getInlineImmVal16(unsigned Imm) {
600d88c1a5aSDimitry Andric switch (Imm) {
601d88c1a5aSDimitry Andric case 240:
602d88c1a5aSDimitry Andric return 0x3800;
603d88c1a5aSDimitry Andric case 241:
604d88c1a5aSDimitry Andric return 0xB800;
605d88c1a5aSDimitry Andric case 242:
606d88c1a5aSDimitry Andric return 0x3C00;
607d88c1a5aSDimitry Andric case 243:
608d88c1a5aSDimitry Andric return 0xBC00;
609d88c1a5aSDimitry Andric case 244:
610d88c1a5aSDimitry Andric return 0x4000;
611d88c1a5aSDimitry Andric case 245:
612d88c1a5aSDimitry Andric return 0xC000;
613d88c1a5aSDimitry Andric case 246:
614d88c1a5aSDimitry Andric return 0x4400;
615d88c1a5aSDimitry Andric case 247:
616d88c1a5aSDimitry Andric return 0xC400;
617d88c1a5aSDimitry Andric case 248: // 1 / (2 * PI)
618d88c1a5aSDimitry Andric return 0x3118;
619d88c1a5aSDimitry Andric default:
620d88c1a5aSDimitry Andric llvm_unreachable("invalid fp inline imm");
621d88c1a5aSDimitry Andric }
622d88c1a5aSDimitry Andric }
623d88c1a5aSDimitry Andric
decodeFPImmed(OpWidthTy Width,unsigned Imm)624d88c1a5aSDimitry Andric MCOperand AMDGPUDisassembler::decodeFPImmed(OpWidthTy Width, unsigned Imm) {
6253ca95b02SDimitry Andric assert(Imm >= AMDGPU::EncValues::INLINE_FLOATING_C_MIN
6263ca95b02SDimitry Andric && Imm <= AMDGPU::EncValues::INLINE_FLOATING_C_MAX);
627d88c1a5aSDimitry Andric
6283ca95b02SDimitry Andric // ToDo: case 248: 1/(2*PI) - is allowed only on VI
629d88c1a5aSDimitry Andric switch (Width) {
630d88c1a5aSDimitry Andric case OPW32:
631d88c1a5aSDimitry Andric return MCOperand::createImm(getInlineImmVal32(Imm));
632d88c1a5aSDimitry Andric case OPW64:
633d88c1a5aSDimitry Andric return MCOperand::createImm(getInlineImmVal64(Imm));
634d88c1a5aSDimitry Andric case OPW16:
6357a7e6055SDimitry Andric case OPWV216:
636d88c1a5aSDimitry Andric return MCOperand::createImm(getInlineImmVal16(Imm));
637d88c1a5aSDimitry Andric default:
638d88c1a5aSDimitry Andric llvm_unreachable("implement me");
6393ca95b02SDimitry Andric }
6403ca95b02SDimitry Andric }
6413ca95b02SDimitry Andric
getVgprClassId(const OpWidthTy Width) const6423ca95b02SDimitry Andric unsigned AMDGPUDisassembler::getVgprClassId(const OpWidthTy Width) const {
6433ca95b02SDimitry Andric using namespace AMDGPU;
6442cab237bSDimitry Andric
6453ca95b02SDimitry Andric assert(OPW_FIRST_ <= Width && Width < OPW_LAST_);
6463ca95b02SDimitry Andric switch (Width) {
6473ca95b02SDimitry Andric default: // fall
648d88c1a5aSDimitry Andric case OPW32:
649d88c1a5aSDimitry Andric case OPW16:
6507a7e6055SDimitry Andric case OPWV216:
651d88c1a5aSDimitry Andric return VGPR_32RegClassID;
6523ca95b02SDimitry Andric case OPW64: return VReg_64RegClassID;
6533ca95b02SDimitry Andric case OPW128: return VReg_128RegClassID;
6543ca95b02SDimitry Andric }
6553ca95b02SDimitry Andric }
6563ca95b02SDimitry Andric
getSgprClassId(const OpWidthTy Width) const6573ca95b02SDimitry Andric unsigned AMDGPUDisassembler::getSgprClassId(const OpWidthTy Width) const {
6583ca95b02SDimitry Andric using namespace AMDGPU;
6592cab237bSDimitry Andric
6603ca95b02SDimitry Andric assert(OPW_FIRST_ <= Width && Width < OPW_LAST_);
6613ca95b02SDimitry Andric switch (Width) {
6623ca95b02SDimitry Andric default: // fall
663d88c1a5aSDimitry Andric case OPW32:
664d88c1a5aSDimitry Andric case OPW16:
6657a7e6055SDimitry Andric case OPWV216:
666d88c1a5aSDimitry Andric return SGPR_32RegClassID;
6673ca95b02SDimitry Andric case OPW64: return SGPR_64RegClassID;
6683ca95b02SDimitry Andric case OPW128: return SGPR_128RegClassID;
669da09e106SDimitry Andric case OPW256: return SGPR_256RegClassID;
670da09e106SDimitry Andric case OPW512: return SGPR_512RegClassID;
6713ca95b02SDimitry Andric }
6723ca95b02SDimitry Andric }
6733ca95b02SDimitry Andric
getTtmpClassId(const OpWidthTy Width) const6743ca95b02SDimitry Andric unsigned AMDGPUDisassembler::getTtmpClassId(const OpWidthTy Width) const {
6753ca95b02SDimitry Andric using namespace AMDGPU;
6762cab237bSDimitry Andric
6773ca95b02SDimitry Andric assert(OPW_FIRST_ <= Width && Width < OPW_LAST_);
6783ca95b02SDimitry Andric switch (Width) {
6793ca95b02SDimitry Andric default: // fall
680d88c1a5aSDimitry Andric case OPW32:
681d88c1a5aSDimitry Andric case OPW16:
6827a7e6055SDimitry Andric case OPWV216:
683d88c1a5aSDimitry Andric return TTMP_32RegClassID;
6843ca95b02SDimitry Andric case OPW64: return TTMP_64RegClassID;
6853ca95b02SDimitry Andric case OPW128: return TTMP_128RegClassID;
686da09e106SDimitry Andric case OPW256: return TTMP_256RegClassID;
687da09e106SDimitry Andric case OPW512: return TTMP_512RegClassID;
6883ca95b02SDimitry Andric }
6893ca95b02SDimitry Andric }
6903ca95b02SDimitry Andric
getTTmpIdx(unsigned Val) const6912cab237bSDimitry Andric int AMDGPUDisassembler::getTTmpIdx(unsigned Val) const {
6922cab237bSDimitry Andric using namespace AMDGPU::EncValues;
6932cab237bSDimitry Andric
6942cab237bSDimitry Andric unsigned TTmpMin = isGFX9() ? TTMP_GFX9_MIN : TTMP_VI_MIN;
6952cab237bSDimitry Andric unsigned TTmpMax = isGFX9() ? TTMP_GFX9_MAX : TTMP_VI_MAX;
6962cab237bSDimitry Andric
6972cab237bSDimitry Andric return (TTmpMin <= Val && Val <= TTmpMax)? Val - TTmpMin : -1;
6982cab237bSDimitry Andric }
6992cab237bSDimitry Andric
decodeSrcOp(const OpWidthTy Width,unsigned Val) const7003ca95b02SDimitry Andric MCOperand AMDGPUDisassembler::decodeSrcOp(const OpWidthTy Width, unsigned Val) const {
7013ca95b02SDimitry Andric using namespace AMDGPU::EncValues;
7022cab237bSDimitry Andric
7033ca95b02SDimitry Andric assert(Val < 512); // enum9
7043ca95b02SDimitry Andric
7053ca95b02SDimitry Andric if (VGPR_MIN <= Val && Val <= VGPR_MAX) {
7063ca95b02SDimitry Andric return createRegOperand(getVgprClassId(Width), Val - VGPR_MIN);
7073ca95b02SDimitry Andric }
7083ca95b02SDimitry Andric if (Val <= SGPR_MAX) {
7093ca95b02SDimitry Andric assert(SGPR_MIN == 0); // "SGPR_MIN <= Val" is always true and causes compilation warning.
7103ca95b02SDimitry Andric return createSRegOperand(getSgprClassId(Width), Val - SGPR_MIN);
7113ca95b02SDimitry Andric }
7122cab237bSDimitry Andric
7132cab237bSDimitry Andric int TTmpIdx = getTTmpIdx(Val);
7142cab237bSDimitry Andric if (TTmpIdx >= 0) {
7152cab237bSDimitry Andric return createSRegOperand(getTtmpClassId(Width), TTmpIdx);
7163ca95b02SDimitry Andric }
7173ca95b02SDimitry Andric
7183ca95b02SDimitry Andric if (INLINE_INTEGER_C_MIN <= Val && Val <= INLINE_INTEGER_C_MAX)
7193ca95b02SDimitry Andric return decodeIntImmed(Val);
7203ca95b02SDimitry Andric
7213ca95b02SDimitry Andric if (INLINE_FLOATING_C_MIN <= Val && Val <= INLINE_FLOATING_C_MAX)
722d88c1a5aSDimitry Andric return decodeFPImmed(Width, Val);
7233ca95b02SDimitry Andric
7243ca95b02SDimitry Andric if (Val == LITERAL_CONST)
7253ca95b02SDimitry Andric return decodeLiteralConstant();
7263ca95b02SDimitry Andric
727d88c1a5aSDimitry Andric switch (Width) {
728d88c1a5aSDimitry Andric case OPW32:
729d88c1a5aSDimitry Andric case OPW16:
7307a7e6055SDimitry Andric case OPWV216:
731d88c1a5aSDimitry Andric return decodeSpecialReg32(Val);
732d88c1a5aSDimitry Andric case OPW64:
733d88c1a5aSDimitry Andric return decodeSpecialReg64(Val);
734d88c1a5aSDimitry Andric default:
735d88c1a5aSDimitry Andric llvm_unreachable("unexpected immediate type");
736d88c1a5aSDimitry Andric }
7373ca95b02SDimitry Andric }
7383ca95b02SDimitry Andric
decodeDstOp(const OpWidthTy Width,unsigned Val) const739da09e106SDimitry Andric MCOperand AMDGPUDisassembler::decodeDstOp(const OpWidthTy Width, unsigned Val) const {
740da09e106SDimitry Andric using namespace AMDGPU::EncValues;
741da09e106SDimitry Andric
742da09e106SDimitry Andric assert(Val < 128);
743da09e106SDimitry Andric assert(Width == OPW256 || Width == OPW512);
744da09e106SDimitry Andric
745da09e106SDimitry Andric if (Val <= SGPR_MAX) {
746da09e106SDimitry Andric assert(SGPR_MIN == 0); // "SGPR_MIN <= Val" is always true and causes compilation warning.
747da09e106SDimitry Andric return createSRegOperand(getSgprClassId(Width), Val - SGPR_MIN);
748da09e106SDimitry Andric }
749da09e106SDimitry Andric
750da09e106SDimitry Andric int TTmpIdx = getTTmpIdx(Val);
751da09e106SDimitry Andric if (TTmpIdx >= 0) {
752da09e106SDimitry Andric return createSRegOperand(getTtmpClassId(Width), TTmpIdx);
753da09e106SDimitry Andric }
754da09e106SDimitry Andric
755da09e106SDimitry Andric llvm_unreachable("unknown dst register");
756da09e106SDimitry Andric }
757da09e106SDimitry Andric
decodeSpecialReg32(unsigned Val) const7583ca95b02SDimitry Andric MCOperand AMDGPUDisassembler::decodeSpecialReg32(unsigned Val) const {
7593ca95b02SDimitry Andric using namespace AMDGPU;
7602cab237bSDimitry Andric
7613ca95b02SDimitry Andric switch (Val) {
7622cab237bSDimitry Andric case 102: return createRegOperand(FLAT_SCR_LO);
7632cab237bSDimitry Andric case 103: return createRegOperand(FLAT_SCR_HI);
764*4ba319b5SDimitry Andric case 104: return createRegOperand(XNACK_MASK_LO);
765*4ba319b5SDimitry Andric case 105: return createRegOperand(XNACK_MASK_HI);
7663ca95b02SDimitry Andric case 106: return createRegOperand(VCC_LO);
7673ca95b02SDimitry Andric case 107: return createRegOperand(VCC_HI);
7682cab237bSDimitry Andric case 108: assert(!isGFX9()); return createRegOperand(TBA_LO);
7692cab237bSDimitry Andric case 109: assert(!isGFX9()); return createRegOperand(TBA_HI);
7702cab237bSDimitry Andric case 110: assert(!isGFX9()); return createRegOperand(TMA_LO);
7712cab237bSDimitry Andric case 111: assert(!isGFX9()); return createRegOperand(TMA_HI);
7723ca95b02SDimitry Andric case 124: return createRegOperand(M0);
7733ca95b02SDimitry Andric case 126: return createRegOperand(EXEC_LO);
7743ca95b02SDimitry Andric case 127: return createRegOperand(EXEC_HI);
7757a7e6055SDimitry Andric case 235: return createRegOperand(SRC_SHARED_BASE);
7767a7e6055SDimitry Andric case 236: return createRegOperand(SRC_SHARED_LIMIT);
7777a7e6055SDimitry Andric case 237: return createRegOperand(SRC_PRIVATE_BASE);
7787a7e6055SDimitry Andric case 238: return createRegOperand(SRC_PRIVATE_LIMIT);
7797a7e6055SDimitry Andric // TODO: SRC_POPS_EXITING_WAVE_ID
7803ca95b02SDimitry Andric // ToDo: no support for vccz register
7813ca95b02SDimitry Andric case 251: break;
7823ca95b02SDimitry Andric // ToDo: no support for execz register
7833ca95b02SDimitry Andric case 252: break;
7843ca95b02SDimitry Andric case 253: return createRegOperand(SCC);
7853ca95b02SDimitry Andric default: break;
7863ca95b02SDimitry Andric }
7873ca95b02SDimitry Andric return errOperand(Val, "unknown operand encoding " + Twine(Val));
7883ca95b02SDimitry Andric }
7893ca95b02SDimitry Andric
decodeSpecialReg64(unsigned Val) const7903ca95b02SDimitry Andric MCOperand AMDGPUDisassembler::decodeSpecialReg64(unsigned Val) const {
7913ca95b02SDimitry Andric using namespace AMDGPU;
7922cab237bSDimitry Andric
7933ca95b02SDimitry Andric switch (Val) {
7942cab237bSDimitry Andric case 102: return createRegOperand(FLAT_SCR);
795*4ba319b5SDimitry Andric case 104: return createRegOperand(XNACK_MASK);
7963ca95b02SDimitry Andric case 106: return createRegOperand(VCC);
7972cab237bSDimitry Andric case 108: assert(!isGFX9()); return createRegOperand(TBA);
7982cab237bSDimitry Andric case 110: assert(!isGFX9()); return createRegOperand(TMA);
7993ca95b02SDimitry Andric case 126: return createRegOperand(EXEC);
8003ca95b02SDimitry Andric default: break;
8013ca95b02SDimitry Andric }
8023ca95b02SDimitry Andric return errOperand(Val, "unknown operand encoding " + Twine(Val));
8033ca95b02SDimitry Andric }
8043ca95b02SDimitry Andric
decodeSDWASrc(const OpWidthTy Width,const unsigned Val) const805edd7eaddSDimitry Andric MCOperand AMDGPUDisassembler::decodeSDWASrc(const OpWidthTy Width,
806*4ba319b5SDimitry Andric const unsigned Val) const {
807302affcbSDimitry Andric using namespace AMDGPU::SDWA;
808*4ba319b5SDimitry Andric using namespace AMDGPU::EncValues;
809302affcbSDimitry Andric
810edd7eaddSDimitry Andric if (STI.getFeatureBits()[AMDGPU::FeatureGFX9]) {
811a580b014SDimitry Andric // XXX: static_cast<int> is needed to avoid stupid warning:
812a580b014SDimitry Andric // compare with unsigned is always true
813a580b014SDimitry Andric if (SDWA9EncValues::SRC_VGPR_MIN <= static_cast<int>(Val) &&
814302affcbSDimitry Andric Val <= SDWA9EncValues::SRC_VGPR_MAX) {
815302affcbSDimitry Andric return createRegOperand(getVgprClassId(Width),
816302affcbSDimitry Andric Val - SDWA9EncValues::SRC_VGPR_MIN);
817302affcbSDimitry Andric }
818302affcbSDimitry Andric if (SDWA9EncValues::SRC_SGPR_MIN <= Val &&
819302affcbSDimitry Andric Val <= SDWA9EncValues::SRC_SGPR_MAX) {
820302affcbSDimitry Andric return createSRegOperand(getSgprClassId(Width),
821302affcbSDimitry Andric Val - SDWA9EncValues::SRC_SGPR_MIN);
822302affcbSDimitry Andric }
8232cab237bSDimitry Andric if (SDWA9EncValues::SRC_TTMP_MIN <= Val &&
8242cab237bSDimitry Andric Val <= SDWA9EncValues::SRC_TTMP_MAX) {
8252cab237bSDimitry Andric return createSRegOperand(getTtmpClassId(Width),
8262cab237bSDimitry Andric Val - SDWA9EncValues::SRC_TTMP_MIN);
8272cab237bSDimitry Andric }
828302affcbSDimitry Andric
829*4ba319b5SDimitry Andric const unsigned SVal = Val - SDWA9EncValues::SRC_SGPR_MIN;
830*4ba319b5SDimitry Andric
831*4ba319b5SDimitry Andric if (INLINE_INTEGER_C_MIN <= SVal && SVal <= INLINE_INTEGER_C_MAX)
832*4ba319b5SDimitry Andric return decodeIntImmed(SVal);
833*4ba319b5SDimitry Andric
834*4ba319b5SDimitry Andric if (INLINE_FLOATING_C_MIN <= SVal && SVal <= INLINE_FLOATING_C_MAX)
835*4ba319b5SDimitry Andric return decodeFPImmed(Width, SVal);
836*4ba319b5SDimitry Andric
837*4ba319b5SDimitry Andric return decodeSpecialReg32(SVal);
838edd7eaddSDimitry Andric } else if (STI.getFeatureBits()[AMDGPU::FeatureVolcanicIslands]) {
839edd7eaddSDimitry Andric return createRegOperand(getVgprClassId(Width), Val);
840edd7eaddSDimitry Andric }
841edd7eaddSDimitry Andric llvm_unreachable("unsupported target");
842302affcbSDimitry Andric }
843302affcbSDimitry Andric
decodeSDWASrc16(unsigned Val) const844edd7eaddSDimitry Andric MCOperand AMDGPUDisassembler::decodeSDWASrc16(unsigned Val) const {
845edd7eaddSDimitry Andric return decodeSDWASrc(OPW16, Val);
846302affcbSDimitry Andric }
847302affcbSDimitry Andric
decodeSDWASrc32(unsigned Val) const848edd7eaddSDimitry Andric MCOperand AMDGPUDisassembler::decodeSDWASrc32(unsigned Val) const {
849edd7eaddSDimitry Andric return decodeSDWASrc(OPW32, Val);
850302affcbSDimitry Andric }
851302affcbSDimitry Andric
decodeSDWAVopcDst(unsigned Val) const852edd7eaddSDimitry Andric MCOperand AMDGPUDisassembler::decodeSDWAVopcDst(unsigned Val) const {
853302affcbSDimitry Andric using namespace AMDGPU::SDWA;
854302affcbSDimitry Andric
855edd7eaddSDimitry Andric assert(STI.getFeatureBits()[AMDGPU::FeatureGFX9] &&
856edd7eaddSDimitry Andric "SDWAVopcDst should be present only on GFX9");
857302affcbSDimitry Andric if (Val & SDWA9EncValues::VOPC_DST_VCC_MASK) {
858302affcbSDimitry Andric Val &= SDWA9EncValues::VOPC_DST_SGPR_MASK;
8592cab237bSDimitry Andric
8602cab237bSDimitry Andric int TTmpIdx = getTTmpIdx(Val);
8612cab237bSDimitry Andric if (TTmpIdx >= 0) {
8622cab237bSDimitry Andric return createSRegOperand(getTtmpClassId(OPW64), TTmpIdx);
8632cab237bSDimitry Andric } else if (Val > AMDGPU::EncValues::SGPR_MAX) {
864302affcbSDimitry Andric return decodeSpecialReg64(Val);
865302affcbSDimitry Andric } else {
866302affcbSDimitry Andric return createSRegOperand(getSgprClassId(OPW64), Val);
867302affcbSDimitry Andric }
868302affcbSDimitry Andric } else {
869302affcbSDimitry Andric return createRegOperand(AMDGPU::VCC);
870302affcbSDimitry Andric }
871302affcbSDimitry Andric }
872302affcbSDimitry Andric
isVI() const8732cab237bSDimitry Andric bool AMDGPUDisassembler::isVI() const {
8742cab237bSDimitry Andric return STI.getFeatureBits()[AMDGPU::FeatureVolcanicIslands];
8752cab237bSDimitry Andric }
8762cab237bSDimitry Andric
isGFX9() const8772cab237bSDimitry Andric bool AMDGPUDisassembler::isGFX9() const {
8782cab237bSDimitry Andric return STI.getFeatureBits()[AMDGPU::FeatureGFX9];
8792cab237bSDimitry Andric }
8802cab237bSDimitry Andric
881d88c1a5aSDimitry Andric //===----------------------------------------------------------------------===//
882d88c1a5aSDimitry Andric // AMDGPUSymbolizer
883d88c1a5aSDimitry Andric //===----------------------------------------------------------------------===//
884d88c1a5aSDimitry Andric
885d88c1a5aSDimitry Andric // Try to find symbol name for specified label
tryAddingSymbolicOperand(MCInst & Inst,raw_ostream &,int64_t Value,uint64_t,bool IsBranch,uint64_t,uint64_t)886d88c1a5aSDimitry Andric bool AMDGPUSymbolizer::tryAddingSymbolicOperand(MCInst &Inst,
887d88c1a5aSDimitry Andric raw_ostream &/*cStream*/, int64_t Value,
888d88c1a5aSDimitry Andric uint64_t /*Address*/, bool IsBranch,
889d88c1a5aSDimitry Andric uint64_t /*Offset*/, uint64_t /*InstSize*/) {
8902cab237bSDimitry Andric using SymbolInfoTy = std::tuple<uint64_t, StringRef, uint8_t>;
8912cab237bSDimitry Andric using SectionSymbolsTy = std::vector<SymbolInfoTy>;
892d88c1a5aSDimitry Andric
893d88c1a5aSDimitry Andric if (!IsBranch) {
894d88c1a5aSDimitry Andric return false;
895d88c1a5aSDimitry Andric }
896d88c1a5aSDimitry Andric
897d88c1a5aSDimitry Andric auto *Symbols = static_cast<SectionSymbolsTy *>(DisInfo);
898*4ba319b5SDimitry Andric if (!Symbols)
899*4ba319b5SDimitry Andric return false;
900*4ba319b5SDimitry Andric
901d88c1a5aSDimitry Andric auto Result = std::find_if(Symbols->begin(), Symbols->end(),
902d88c1a5aSDimitry Andric [Value](const SymbolInfoTy& Val) {
903d88c1a5aSDimitry Andric return std::get<0>(Val) == static_cast<uint64_t>(Value)
904d88c1a5aSDimitry Andric && std::get<2>(Val) == ELF::STT_NOTYPE;
905d88c1a5aSDimitry Andric });
906d88c1a5aSDimitry Andric if (Result != Symbols->end()) {
907d88c1a5aSDimitry Andric auto *Sym = Ctx.getOrCreateSymbol(std::get<1>(*Result));
908d88c1a5aSDimitry Andric const auto *Add = MCSymbolRefExpr::create(Sym, Ctx);
909d88c1a5aSDimitry Andric Inst.addOperand(MCOperand::createExpr(Add));
910d88c1a5aSDimitry Andric return true;
911d88c1a5aSDimitry Andric }
912d88c1a5aSDimitry Andric return false;
913d88c1a5aSDimitry Andric }
914d88c1a5aSDimitry Andric
tryAddingPcLoadReferenceComment(raw_ostream & cStream,int64_t Value,uint64_t Address)915d88c1a5aSDimitry Andric void AMDGPUSymbolizer::tryAddingPcLoadReferenceComment(raw_ostream &cStream,
916d88c1a5aSDimitry Andric int64_t Value,
917d88c1a5aSDimitry Andric uint64_t Address) {
918d88c1a5aSDimitry Andric llvm_unreachable("unimplemented");
919d88c1a5aSDimitry Andric }
920d88c1a5aSDimitry Andric
921d88c1a5aSDimitry Andric //===----------------------------------------------------------------------===//
922d88c1a5aSDimitry Andric // Initialization
923d88c1a5aSDimitry Andric //===----------------------------------------------------------------------===//
924d88c1a5aSDimitry Andric
createAMDGPUSymbolizer(const Triple &,LLVMOpInfoCallback,LLVMSymbolLookupCallback,void * DisInfo,MCContext * Ctx,std::unique_ptr<MCRelocationInfo> && RelInfo)925d88c1a5aSDimitry Andric static MCSymbolizer *createAMDGPUSymbolizer(const Triple &/*TT*/,
926d88c1a5aSDimitry Andric LLVMOpInfoCallback /*GetOpInfo*/,
927d88c1a5aSDimitry Andric LLVMSymbolLookupCallback /*SymbolLookUp*/,
928d88c1a5aSDimitry Andric void *DisInfo,
929d88c1a5aSDimitry Andric MCContext *Ctx,
930d88c1a5aSDimitry Andric std::unique_ptr<MCRelocationInfo> &&RelInfo) {
931d88c1a5aSDimitry Andric return new AMDGPUSymbolizer(*Ctx, std::move(RelInfo), DisInfo);
932d88c1a5aSDimitry Andric }
933d88c1a5aSDimitry Andric
createAMDGPUDisassembler(const Target & T,const MCSubtargetInfo & STI,MCContext & Ctx)9343ca95b02SDimitry Andric static MCDisassembler *createAMDGPUDisassembler(const Target &T,
9353ca95b02SDimitry Andric const MCSubtargetInfo &STI,
9363ca95b02SDimitry Andric MCContext &Ctx) {
9372cab237bSDimitry Andric return new AMDGPUDisassembler(STI, Ctx, T.createMCInstrInfo());
9383ca95b02SDimitry Andric }
9393ca95b02SDimitry Andric
LLVMInitializeAMDGPUDisassembler()9403ca95b02SDimitry Andric extern "C" void LLVMInitializeAMDGPUDisassembler() {
941d88c1a5aSDimitry Andric TargetRegistry::RegisterMCDisassembler(getTheGCNTarget(),
942d88c1a5aSDimitry Andric createAMDGPUDisassembler);
943d88c1a5aSDimitry Andric TargetRegistry::RegisterMCSymbolizer(getTheGCNTarget(),
944d88c1a5aSDimitry Andric createAMDGPUSymbolizer);
9453ca95b02SDimitry Andric }
946