diff options
Diffstat (limited to 'lib/Target/AMDGPU/Disassembler')
| -rw-r--r-- | lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.cpp | 152 | ||||
| -rw-r--r-- | lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.h | 28 | 
2 files changed, 143 insertions, 37 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() { diff --git a/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.h b/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.h index 4c755be09999..ce396eb68c4c 100644 --- a/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.h +++ b/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.h @@ -1,4 +1,4 @@ -//===-- AMDGPUDisassembler.hpp - Disassembler for AMDGPU ISA ---*- C++ -*--===// +//===- AMDGPUDisassembler.hpp - Disassembler for AMDGPU ISA -----*- C++ -*-===//  //  //                     The LLVM Compiler Infrastructure  // @@ -17,16 +17,18 @@  #define LLVM_LIB_TARGET_AMDGPU_DISASSEMBLER_AMDGPUDISASSEMBLER_H  #include "llvm/ADT/ArrayRef.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCInstrInfo.h"  #include "llvm/MC/MCDisassembler/MCDisassembler.h"  #include "llvm/MC/MCDisassembler/MCRelocationInfo.h"  #include "llvm/MC/MCDisassembler/MCSymbolizer.h" +  #include <algorithm>  #include <cstdint>  #include <memory>  namespace llvm { -class MCContext;  class MCInst;  class MCOperand;  class MCSubtargetInfo; @@ -38,13 +40,16 @@ class Twine;  class AMDGPUDisassembler : public MCDisassembler {  private: +  std::unique_ptr<MCInstrInfo const> const MCII; +  const MCRegisterInfo &MRI;    mutable ArrayRef<uint8_t> Bytes;    mutable uint32_t Literal;    mutable bool HasLiteral;  public: -  AMDGPUDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx) : -    MCDisassembler(STI, Ctx) {} +  AMDGPUDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx, +                     MCInstrInfo const *MCII) : +    MCDisassembler(STI, Ctx), MCII(MCII), MRI(*Ctx.getRegisterInfo()) {}    ~AMDGPUDisassembler() override = default; @@ -60,12 +65,11 @@ public:    MCOperand errOperand(unsigned V, const Twine& ErrMsg) const; -  DecodeStatus tryDecodeInst(const uint8_t* Table, -                              MCInst &MI, -                              uint64_t Inst, -                              uint64_t Address) const; +  DecodeStatus tryDecodeInst(const uint8_t* Table, MCInst &MI, uint64_t Inst, +                             uint64_t Address) const;    DecodeStatus convertSDWAInst(MCInst &MI) const; +  DecodeStatus convertMIMGInst(MCInst &MI) const;    MCOperand decodeOperand_VGPR_32(unsigned Val) const;    MCOperand decodeOperand_VS_32(unsigned Val) const; @@ -80,6 +84,7 @@ public:    MCOperand decodeOperand_SReg_32(unsigned Val) const;    MCOperand decodeOperand_SReg_32_XM0_XEXEC(unsigned Val) const; +  MCOperand decodeOperand_SReg_32_XEXEC_HI(unsigned Val) const;    MCOperand decodeOperand_SReg_64(unsigned Val) const;    MCOperand decodeOperand_SReg_64_XEXEC(unsigned Val) const;    MCOperand decodeOperand_SReg_128(unsigned Val) const; @@ -112,7 +117,12 @@ public:    MCOperand decodeSDWASrc16(unsigned Val) const;    MCOperand decodeSDWASrc32(unsigned Val) const;    MCOperand decodeSDWAVopcDst(unsigned Val) const; -}; + +  int getTTmpIdx(unsigned Val) const; + +  bool isVI() const; +  bool isGFX9() const; +  };  //===----------------------------------------------------------------------===//  // AMDGPUSymbolizer  | 
