summaryrefslogtreecommitdiff
path: root/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.cpp')
-rw-r--r--lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.cpp152
1 files changed, 124 insertions, 28 deletions
diff --git a/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.cpp b/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.cpp
index 966c6fec20c6..4a3f2c975179 100644
--- a/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.cpp
+++ b/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.cpp
@@ -1,4 +1,4 @@
-//===-- AMDGPUDisassembler.cpp - Disassembler for AMDGPU ISA --------------===//
+//===- AMDGPUDisassembler.cpp - Disassembler for AMDGPU ISA ---------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -17,29 +17,40 @@
// ToDo: What to do with instruction suffixes (v_mov_b32 vs v_mov_b32_e32)?
-#include "AMDGPUDisassembler.h"
+#include "Disassembler/AMDGPUDisassembler.h"
#include "AMDGPU.h"
#include "AMDGPURegisterInfo.h"
-#include "MCTargetDesc/AMDGPUMCTargetDesc.h"
#include "SIDefines.h"
#include "Utils/AMDGPUBaseInfo.h"
-
+#include "llvm-c/Disassembler.h"
+#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/Twine.h"
#include "llvm/BinaryFormat/ELF.h"
#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCDisassembler/MCDisassembler.h"
+#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCFixedLenDisassembler.h"
#include "llvm/MC/MCInst.h"
-#include "llvm/MC/MCInstrDesc.h"
#include "llvm/MC/MCSubtargetInfo.h"
-#include "llvm/Support/Debug.h"
#include "llvm/Support/Endian.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MathExtras.h"
#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <iterator>
+#include <tuple>
+#include <vector>
using namespace llvm;
#define DEBUG_TYPE "amdgpu-disassembler"
-typedef llvm::MCDisassembler::DecodeStatus DecodeStatus;
-
+using DecodeStatus = llvm::MCDisassembler::DecodeStatus;
inline static MCDisassembler::DecodeStatus
addOperand(MCInst &Inst, const MCOperand& Opnd) {
@@ -95,13 +106,13 @@ DECODE_OPERAND_REG(VReg_128)
DECODE_OPERAND_REG(SReg_32)
DECODE_OPERAND_REG(SReg_32_XM0_XEXEC)
+DECODE_OPERAND_REG(SReg_32_XEXEC_HI)
DECODE_OPERAND_REG(SReg_64)
DECODE_OPERAND_REG(SReg_64_XEXEC)
DECODE_OPERAND_REG(SReg_128)
DECODE_OPERAND_REG(SReg_256)
DECODE_OPERAND_REG(SReg_512)
-
static DecodeStatus decodeOperand_VSrc16(MCInst &Inst,
unsigned Imm,
uint64_t Addr,
@@ -201,12 +212,18 @@ DecodeStatus AMDGPUDisassembler::getInstruction(MCInst &MI, uint64_t &Size,
Res = tryDecodeInst(DecoderTableAMDGPU32, MI, DW, Address);
if (Res) break;
+ Res = tryDecodeInst(DecoderTableGFX932, MI, DW, Address);
+ if (Res) break;
+
if (Bytes.size() < 4) break;
const uint64_t QW = ((uint64_t)eatBytes<uint32_t>(Bytes) << 32) | DW;
Res = tryDecodeInst(DecoderTableVI64, MI, QW, Address);
if (Res) break;
Res = tryDecodeInst(DecoderTableAMDGPU64, MI, QW, Address);
+ if (Res) break;
+
+ Res = tryDecodeInst(DecoderTableGFX964, MI, QW, Address);
} while (false);
if (Res && (MI.getOpcode() == AMDGPU::V_MAC_F32_e64_vi ||
@@ -217,6 +234,10 @@ DecodeStatus AMDGPUDisassembler::getInstruction(MCInst &MI, uint64_t &Size,
AMDGPU::OpName::src2_modifiers);
}
+ if (Res && (MCII->get(MI.getOpcode()).TSFlags & SIInstrFlags::MIMG)) {
+ Res = convertMIMGInst(MI);
+ }
+
if (Res && IsSDWA)
Res = convertSDWAInst(MI);
@@ -233,7 +254,7 @@ DecodeStatus AMDGPUDisassembler::convertSDWAInst(MCInst &MI) const {
int SDst = AMDGPU::getNamedOperandIdx(MI.getOpcode(), AMDGPU::OpName::sdst);
if (SDst != -1) {
// VOPC - insert VCC register as sdst
- insertNamedMCOperand(MI, MCOperand::createReg(AMDGPU::VCC),
+ insertNamedMCOperand(MI, createRegOperand(AMDGPU::VCC),
AMDGPU::OpName::sdst);
} else {
// VOP1/2 - insert omod if present in instruction
@@ -243,6 +264,42 @@ DecodeStatus AMDGPUDisassembler::convertSDWAInst(MCInst &MI) const {
return MCDisassembler::Success;
}
+DecodeStatus AMDGPUDisassembler::convertMIMGInst(MCInst &MI) const {
+ int VDataIdx = AMDGPU::getNamedOperandIdx(MI.getOpcode(),
+ AMDGPU::OpName::vdata);
+
+ int DMaskIdx = AMDGPU::getNamedOperandIdx(MI.getOpcode(),
+ AMDGPU::OpName::dmask);
+ unsigned DMask = MI.getOperand(DMaskIdx).getImm() & 0xf;
+ if (DMask == 0)
+ return MCDisassembler::Success;
+
+ unsigned ChannelCount = countPopulation(DMask);
+ if (ChannelCount == 1)
+ return MCDisassembler::Success;
+
+ int NewOpcode = AMDGPU::getMaskedMIMGOp(*MCII, MI.getOpcode(), ChannelCount);
+ assert(NewOpcode != -1 && "could not find matching mimg channel instruction");
+ auto RCID = MCII->get(NewOpcode).OpInfo[VDataIdx].RegClass;
+
+ // Widen the register to the correct number of enabled channels.
+ unsigned Vdata0 = MI.getOperand(VDataIdx).getReg();
+ auto NewVdata = MRI.getMatchingSuperReg(Vdata0, AMDGPU::sub0,
+ &MRI.getRegClass(RCID));
+ if (NewVdata == AMDGPU::NoRegister) {
+ // It's possible to encode this such that the low register + enabled
+ // components exceeds the register count.
+ return MCDisassembler::Success;
+ }
+
+ MI.setOpcode(NewOpcode);
+ // vaddr will be always appear as a single VGPR. This will look different than
+ // how it is usually emitted because the number of register components is not
+ // in the instruction encoding.
+ MI.getOperand(VDataIdx) = MCOperand::createReg(NewVdata);
+ return MCDisassembler::Success;
+}
+
const char* AMDGPUDisassembler::getRegClassName(unsigned RegClassID) const {
return getContext().getRegisterInfo()->
getRegClassName(&AMDGPUMCRegisterClasses[RegClassID]);
@@ -260,7 +317,7 @@ MCOperand AMDGPUDisassembler::errOperand(unsigned V,
inline
MCOperand AMDGPUDisassembler::createRegOperand(unsigned int RegId) const {
- return MCOperand::createReg(RegId);
+ return MCOperand::createReg(AMDGPU::getMCReg(RegId, STI));
}
inline
@@ -365,6 +422,12 @@ MCOperand AMDGPUDisassembler::decodeOperand_SReg_32_XM0_XEXEC(
return decodeOperand_SReg_32(Val);
}
+MCOperand AMDGPUDisassembler::decodeOperand_SReg_32_XEXEC_HI(
+ unsigned Val) const {
+ // SReg_32_XM0 is SReg_32 without EXEC_HI
+ return decodeOperand_SReg_32(Val);
+}
+
MCOperand AMDGPUDisassembler::decodeOperand_SReg_64(unsigned Val) const {
return decodeSrcOp(OPW64, Val);
}
@@ -385,7 +448,6 @@ MCOperand AMDGPUDisassembler::decodeOperand_SReg_512(unsigned Val) const {
return createSRegOperand(AMDGPU::SReg_512RegClassID, Val);
}
-
MCOperand AMDGPUDisassembler::decodeLiteralConstant() const {
// For now all literal constants are supposed to be unsigned integer
// ToDo: deal with signed/unsigned 64-bit integer constants
@@ -403,6 +465,7 @@ MCOperand AMDGPUDisassembler::decodeLiteralConstant() const {
MCOperand AMDGPUDisassembler::decodeIntImmed(unsigned Imm) {
using namespace AMDGPU::EncValues;
+
assert(Imm >= INLINE_INTEGER_C_MIN && Imm <= INLINE_INTEGER_C_MAX);
return MCOperand::createImm((Imm <= INLINE_INTEGER_C_POSITIVE_MAX) ?
(static_cast<int64_t>(Imm) - INLINE_INTEGER_C_MIN) :
@@ -505,6 +568,7 @@ MCOperand AMDGPUDisassembler::decodeFPImmed(OpWidthTy Width, unsigned Imm) {
unsigned AMDGPUDisassembler::getVgprClassId(const OpWidthTy Width) const {
using namespace AMDGPU;
+
assert(OPW_FIRST_ <= Width && Width < OPW_LAST_);
switch (Width) {
default: // fall
@@ -519,6 +583,7 @@ unsigned AMDGPUDisassembler::getVgprClassId(const OpWidthTy Width) const {
unsigned AMDGPUDisassembler::getSgprClassId(const OpWidthTy Width) const {
using namespace AMDGPU;
+
assert(OPW_FIRST_ <= Width && Width < OPW_LAST_);
switch (Width) {
default: // fall
@@ -533,6 +598,7 @@ unsigned AMDGPUDisassembler::getSgprClassId(const OpWidthTy Width) const {
unsigned AMDGPUDisassembler::getTtmpClassId(const OpWidthTy Width) const {
using namespace AMDGPU;
+
assert(OPW_FIRST_ <= Width && Width < OPW_LAST_);
switch (Width) {
default: // fall
@@ -545,8 +611,18 @@ unsigned AMDGPUDisassembler::getTtmpClassId(const OpWidthTy Width) const {
}
}
+int AMDGPUDisassembler::getTTmpIdx(unsigned Val) const {
+ using namespace AMDGPU::EncValues;
+
+ unsigned TTmpMin = isGFX9() ? TTMP_GFX9_MIN : TTMP_VI_MIN;
+ unsigned TTmpMax = isGFX9() ? TTMP_GFX9_MAX : TTMP_VI_MAX;
+
+ return (TTmpMin <= Val && Val <= TTmpMax)? Val - TTmpMin : -1;
+}
+
MCOperand AMDGPUDisassembler::decodeSrcOp(const OpWidthTy Width, unsigned Val) const {
using namespace AMDGPU::EncValues;
+
assert(Val < 512); // enum9
if (VGPR_MIN <= Val && Val <= VGPR_MAX) {
@@ -556,8 +632,10 @@ MCOperand AMDGPUDisassembler::decodeSrcOp(const OpWidthTy Width, unsigned Val) c
assert(SGPR_MIN == 0); // "SGPR_MIN <= Val" is always true and causes compilation warning.
return createSRegOperand(getSgprClassId(Width), Val - SGPR_MIN);
}
- if (TTMP_MIN <= Val && Val <= TTMP_MAX) {
- return createSRegOperand(getTtmpClassId(Width), Val - TTMP_MIN);
+
+ int TTmpIdx = getTTmpIdx(Val);
+ if (TTmpIdx >= 0) {
+ return createSRegOperand(getTtmpClassId(Width), TTmpIdx);
}
if (INLINE_INTEGER_C_MIN <= Val && Val <= INLINE_INTEGER_C_MAX)
@@ -583,18 +661,19 @@ MCOperand AMDGPUDisassembler::decodeSrcOp(const OpWidthTy Width, unsigned Val) c
MCOperand AMDGPUDisassembler::decodeSpecialReg32(unsigned Val) const {
using namespace AMDGPU;
+
switch (Val) {
- case 102: return createRegOperand(getMCReg(FLAT_SCR_LO, STI));
- case 103: return createRegOperand(getMCReg(FLAT_SCR_HI, STI));
+ case 102: return createRegOperand(FLAT_SCR_LO);
+ case 103: return createRegOperand(FLAT_SCR_HI);
// ToDo: no support for xnack_mask_lo/_hi register
case 104:
case 105: break;
case 106: return createRegOperand(VCC_LO);
case 107: return createRegOperand(VCC_HI);
- case 108: return createRegOperand(TBA_LO);
- case 109: return createRegOperand(TBA_HI);
- case 110: return createRegOperand(TMA_LO);
- case 111: return createRegOperand(TMA_HI);
+ case 108: assert(!isGFX9()); return createRegOperand(TBA_LO);
+ case 109: assert(!isGFX9()); return createRegOperand(TBA_HI);
+ case 110: assert(!isGFX9()); return createRegOperand(TMA_LO);
+ case 111: assert(!isGFX9()); return createRegOperand(TMA_HI);
case 124: return createRegOperand(M0);
case 126: return createRegOperand(EXEC_LO);
case 127: return createRegOperand(EXEC_HI);
@@ -615,11 +694,12 @@ MCOperand AMDGPUDisassembler::decodeSpecialReg32(unsigned Val) const {
MCOperand AMDGPUDisassembler::decodeSpecialReg64(unsigned Val) const {
using namespace AMDGPU;
+
switch (Val) {
- case 102: return createRegOperand(getMCReg(FLAT_SCR, STI));
+ case 102: return createRegOperand(FLAT_SCR);
case 106: return createRegOperand(VCC);
- case 108: return createRegOperand(TBA);
- case 110: return createRegOperand(TMA);
+ case 108: assert(!isGFX9()); return createRegOperand(TBA);
+ case 110: assert(!isGFX9()); return createRegOperand(TMA);
case 126: return createRegOperand(EXEC);
default: break;
}
@@ -643,6 +723,11 @@ MCOperand AMDGPUDisassembler::decodeSDWASrc(const OpWidthTy Width,
return createSRegOperand(getSgprClassId(Width),
Val - SDWA9EncValues::SRC_SGPR_MIN);
}
+ if (SDWA9EncValues::SRC_TTMP_MIN <= Val &&
+ Val <= SDWA9EncValues::SRC_TTMP_MAX) {
+ return createSRegOperand(getTtmpClassId(Width),
+ Val - SDWA9EncValues::SRC_TTMP_MIN);
+ }
return decodeSpecialReg32(Val - SDWA9EncValues::SRC_SGPR_MIN);
} else if (STI.getFeatureBits()[AMDGPU::FeatureVolcanicIslands]) {
@@ -659,7 +744,6 @@ MCOperand AMDGPUDisassembler::decodeSDWASrc32(unsigned Val) const {
return decodeSDWASrc(OPW32, Val);
}
-
MCOperand AMDGPUDisassembler::decodeSDWAVopcDst(unsigned Val) const {
using namespace AMDGPU::SDWA;
@@ -667,7 +751,11 @@ MCOperand AMDGPUDisassembler::decodeSDWAVopcDst(unsigned Val) const {
"SDWAVopcDst should be present only on GFX9");
if (Val & SDWA9EncValues::VOPC_DST_VCC_MASK) {
Val &= SDWA9EncValues::VOPC_DST_SGPR_MASK;
- if (Val > AMDGPU::EncValues::SGPR_MAX) {
+
+ int TTmpIdx = getTTmpIdx(Val);
+ if (TTmpIdx >= 0) {
+ return createSRegOperand(getTtmpClassId(OPW64), TTmpIdx);
+ } else if (Val > AMDGPU::EncValues::SGPR_MAX) {
return decodeSpecialReg64(Val);
} else {
return createSRegOperand(getSgprClassId(OPW64), Val);
@@ -677,6 +765,14 @@ MCOperand AMDGPUDisassembler::decodeSDWAVopcDst(unsigned Val) const {
}
}
+bool AMDGPUDisassembler::isVI() const {
+ return STI.getFeatureBits()[AMDGPU::FeatureVolcanicIslands];
+}
+
+bool AMDGPUDisassembler::isGFX9() const {
+ return STI.getFeatureBits()[AMDGPU::FeatureGFX9];
+}
+
//===----------------------------------------------------------------------===//
// AMDGPUSymbolizer
//===----------------------------------------------------------------------===//
@@ -686,8 +782,8 @@ bool AMDGPUSymbolizer::tryAddingSymbolicOperand(MCInst &Inst,
raw_ostream &/*cStream*/, int64_t Value,
uint64_t /*Address*/, bool IsBranch,
uint64_t /*Offset*/, uint64_t /*InstSize*/) {
- typedef std::tuple<uint64_t, StringRef, uint8_t> SymbolInfoTy;
- typedef std::vector<SymbolInfoTy> SectionSymbolsTy;
+ using SymbolInfoTy = std::tuple<uint64_t, StringRef, uint8_t>;
+ using SectionSymbolsTy = std::vector<SymbolInfoTy>;
if (!IsBranch) {
return false;
@@ -730,7 +826,7 @@ static MCSymbolizer *createAMDGPUSymbolizer(const Triple &/*TT*/,
static MCDisassembler *createAMDGPUDisassembler(const Target &T,
const MCSubtargetInfo &STI,
MCContext &Ctx) {
- return new AMDGPUDisassembler(STI, Ctx);
+ return new AMDGPUDisassembler(STI, Ctx, T.createMCInstrInfo());
}
extern "C" void LLVMInitializeAMDGPUDisassembler() {