diff options
Diffstat (limited to 'lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.cpp')
-rw-r--r-- | lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.cpp | 152 |
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() { |