llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.cpp
Nikolay Haustov acb1111440 [AMDGPU] Disassembler: Support for all VOP1 instructions.
Support all instructions with VOP1 encoding with 32 or 64-bit operands for VI subtarget:

VGPR_32 and VReg_64 operand register classes
VS_32 and VS_64 operand register classes with inline and literal constants
Tests for VOP1 instructions.

Patch by: skolton

Reviewers: arsenm, tstellarAMD

Review: http://reviews.llvm.org/D17194

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@261878 91177308-0d34-0410-b5e6-96231b3b80d8
2016-02-25 16:09:14 +00:00

460 lines
16 KiB
C++

//===-- AMDGPUDisassembler.cpp - Disassembler for AMDGPU ISA --------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//===----------------------------------------------------------------------===//
//
/// \file
///
/// This file contains definition for AMDGPU ISA disassembler
//
//===----------------------------------------------------------------------===//
// ToDo: What to do with instruction suffixes (v_mov_b32 vs v_mov_b32_e32)?
#include "AMDGPUDisassembler.h"
#include "AMDGPU.h"
#include "AMDGPURegisterInfo.h"
#include "Utils/AMDGPUBaseInfo.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/TargetRegistry.h"
using namespace llvm;
#define DEBUG_TYPE "amdgpu-disassembler"
typedef llvm::MCDisassembler::DecodeStatus DecodeStatus;
static DecodeStatus DecodeVGPR_32RegisterClass(MCInst &Inst, unsigned Imm,
uint64_t Addr, const void *Decoder) {
const AMDGPUDisassembler *Dis =
static_cast<const AMDGPUDisassembler *>(Decoder);
return Dis->DecodeVGPR_32RegisterClass(Inst, Imm, Addr);
}
static DecodeStatus DecodeVS_32RegisterClass(MCInst &Inst, unsigned Imm,
uint64_t Addr, const void *Decoder) {
const AMDGPUDisassembler *Dis =
static_cast<const AMDGPUDisassembler *>(Decoder);
return Dis->DecodeVS_32RegisterClass(Inst, Imm, Addr);
}
static DecodeStatus DecodeVS_64RegisterClass(MCInst &Inst, unsigned Imm,
uint64_t Addr, const void *Decoder) {
const AMDGPUDisassembler *Dis =
static_cast<const AMDGPUDisassembler *>(Decoder);
return Dis->DecodeVS_64RegisterClass(Inst, Imm, Addr);
}
static DecodeStatus DecodeVReg_64RegisterClass(MCInst &Inst, unsigned Imm,
uint64_t Addr, const void *Decoder) {
const AMDGPUDisassembler *Dis =
static_cast<const AMDGPUDisassembler *>(Decoder);
return Dis->DecodeVReg_64RegisterClass(Inst, Imm, Addr);
}
static DecodeStatus DecodeVReg_96RegisterClass(MCInst &Inst, unsigned Imm,
uint64_t Addr, const void *Decoder) {
// ToDo
return MCDisassembler::Fail;
}
static DecodeStatus DecodeVReg_128RegisterClass(MCInst &Inst, unsigned Imm,
uint64_t Addr, const void *Decoder) {
// ToDo
return MCDisassembler::Fail;
}
static DecodeStatus DecodeSReg_32RegisterClass(MCInst &Inst, unsigned Imm,
uint64_t Addr, const void *Decoder) {
// ToDo
return MCDisassembler::Fail;
}
static DecodeStatus DecodeSReg_64RegisterClass(MCInst &Inst, unsigned Imm,
uint64_t Addr, const void *Decoder) {
// ToDo
return MCDisassembler::Fail;
}
static DecodeStatus DecodeSReg_128RegisterClass(MCInst &Inst, unsigned Imm,
uint64_t Addr, const void *Decoder) {
// ToDo
return MCDisassembler::Fail;
}
static DecodeStatus DecodeSReg_256RegisterClass(MCInst &Inst, unsigned Imm,
uint64_t Addr, const void *Decoder) {
// ToDo
return MCDisassembler::Fail;
}
#define GET_SUBTARGETINFO_ENUM
#include "AMDGPUGenSubtargetInfo.inc"
#undef GET_SUBTARGETINFO_ENUM
#include "AMDGPUGenDisassemblerTables.inc"
//===----------------------------------------------------------------------===//
//
//===----------------------------------------------------------------------===//
DecodeStatus AMDGPUDisassembler::getInstruction(MCInst &MI, uint64_t &Size,
ArrayRef<uint8_t> Bytes,
uint64_t Address,
raw_ostream &WS,
raw_ostream &CS) const {
CommentStream = &CS;
// ToDo: AMDGPUDisassembler supports only VI ISA.
assert(AMDGPU::isVI(STI) && "Can disassemble only VI ISA.");
HasLiteral = false;
this->Bytes = Bytes;
// Try decode 32-bit instruction
if (Bytes.size() < 4) {
Size = 0;
return MCDisassembler::Fail;
}
uint32_t Insn =
(Bytes[3] << 24) | (Bytes[2] << 16) | (Bytes[1] << 8) | (Bytes[0] << 0);
// Calling the auto-generated decoder function.
DecodeStatus Result =
decodeInstruction(DecoderTableVI32, MI, Insn, Address, this, STI);
if (Result != MCDisassembler::Success) {
Size = 0;
return MCDisassembler::Fail;
}
if (HasLiteral == true) {
Size = 8;
HasLiteral = false;
} else {
Size = 4;
}
return MCDisassembler::Success;
}
DecodeStatus AMDGPUDisassembler::DecodeImmedFloat(unsigned Imm, uint32_t &F) const {
// ToDo: case 248: 1/(2*PI) - is allowed only on VI
// ToDo: AMDGPUInstPrinter does not support 1/(2*PI). It consider 1/(2*PI) as
// literal constant.
switch(Imm) {
case 240: F = FloatToBits(0.5f); return MCDisassembler::Success;
case 241: F = FloatToBits(-0.5f); return MCDisassembler::Success;
case 242: F = FloatToBits(1.0f); return MCDisassembler::Success;
case 243: F = FloatToBits(-1.0f); return MCDisassembler::Success;
case 244: F = FloatToBits(2.0f); return MCDisassembler::Success;
case 245: F = FloatToBits(-2.0f); return MCDisassembler::Success;
case 246: F = FloatToBits(4.0f); return MCDisassembler::Success;
case 247: F = FloatToBits(-4.0f); return MCDisassembler::Success;
case 248: F = 0x3e22f983; return MCDisassembler::Success; // 1/(2*PI)
default: return MCDisassembler::Fail;
}
}
DecodeStatus AMDGPUDisassembler::DecodeImmedDouble(unsigned Imm, uint64_t &D) const {
switch(Imm) {
case 240: D = DoubleToBits(0.5); return MCDisassembler::Success;
case 241: D = DoubleToBits(-0.5); return MCDisassembler::Success;
case 242: D = DoubleToBits(1.0); return MCDisassembler::Success;
case 243: D = DoubleToBits(-1.0); return MCDisassembler::Success;
case 244: D = DoubleToBits(2.0); return MCDisassembler::Success;
case 245: D = DoubleToBits(-2.0); return MCDisassembler::Success;
case 246: D = DoubleToBits(4.0); return MCDisassembler::Success;
case 247: D = DoubleToBits(-4.0); return MCDisassembler::Success;
case 248: D = 0x3fc45f306dc9c882; return MCDisassembler::Success; // 1/(2*PI)
default: return MCDisassembler::Fail;
}
}
DecodeStatus AMDGPUDisassembler::DecodeImmedInteger(unsigned Imm,
int64_t &I) const {
if ((Imm >= 128) && (Imm <= 192)) {
I = Imm - 128;
return MCDisassembler::Success;
} else if ((Imm >= 193) && (Imm <= 208)) {
I = 192 - Imm;
return MCDisassembler::Success;
}
return MCDisassembler::Fail;
}
DecodeStatus AMDGPUDisassembler::DecodeVgprRegister(unsigned Val,
unsigned &RegID,
unsigned Size) const {
if (Val > (256 - Size / 32)) {
return MCDisassembler::Fail;
}
unsigned RegClassID;
switch (Size) {
case 32: RegClassID = AMDGPU::VGPR_32RegClassID; break;
case 64: RegClassID = AMDGPU::VReg_64RegClassID; break;
case 96: RegClassID = AMDGPU::VReg_96RegClassID; break;
case 128: RegClassID = AMDGPU::VReg_128RegClassID; break;
case 256: RegClassID = AMDGPU::VReg_256RegClassID; break;
case 512: RegClassID = AMDGPU::VReg_512RegClassID; break;
default:
return MCDisassembler::Fail;
}
RegID = AMDGPUMCRegisterClasses[RegClassID].getRegister(Val);
return MCDisassembler::Success;
}
DecodeStatus AMDGPUDisassembler::DecodeSgprRegister(unsigned Val,
unsigned &RegID,
unsigned Size) const {
// ToDo: SI/CI have 104 SGPRs, VI - 102
unsigned RegClassID;
switch (Size) {
case 32:
if (Val > 101) {
return MCDisassembler::Fail;
}
RegClassID = AMDGPU::SGPR_32RegClassID;
break;
case 64:
if ((Val % 2 != 0) || (Val > 100)) {
return MCDisassembler::Fail;
}
Val /= 2;
RegClassID = AMDGPU::SGPR_64RegClassID;
break;
case 128:
// ToDo: unclear if s[100:104] is available on VI. Can we use VCC as SGPR in
// this bundle?
if ((Val % 4 != 0) || (Val > 96)) {
return MCDisassembler::Fail;
}
Val /= 4;
RegClassID = AMDGPU::SReg_128RegClassID;
break;
case 256:
// ToDo: unclear if s[96:104] is available on VI. Can we use VCC as SGPR in
// this bundle?
if ((Val % 4 != 0) || (Val > 92)) {
return MCDisassembler::Fail;
}
Val /= 4;
RegClassID = AMDGPU::SReg_256RegClassID;
break;
case 512:
// ToDo: unclear if s[88:104] is available on VI. Can we use VCC as SGPR in
// this bundle?
if ((Val % 4 != 0) || (Val > 84)) {
return MCDisassembler::Fail;
}
Val /= 4;
RegClassID = AMDGPU::SReg_512RegClassID;
break;
default:
return MCDisassembler::Fail;
}
RegID = AMDGPUMCRegisterClasses[RegClassID].getRegister(Val);
return MCDisassembler::Success;
}
DecodeStatus AMDGPUDisassembler::DecodeSrc32Register(unsigned Val,
unsigned &RegID) const {
// ToDo: deal with out-of range registers
using namespace AMDGPU;
if (Val <= 101) {
return DecodeSgprRegister(Val, RegID, 32);
} else if ((Val >= 256) && (Val <= 511)) {
return DecodeVgprRegister(Val - 256, RegID, 32);
} else {
switch(Val) {
case 102: RegID = getMCReg(FLAT_SCR_LO, STI); return MCDisassembler::Success;
case 103: RegID = getMCReg(FLAT_SCR_HI, STI); return MCDisassembler::Success;
// ToDo: no support for xnack_mask_lo/_hi register
case 104:
case 105: return MCDisassembler::Fail;
case 106: RegID = getMCReg(VCC_LO, STI); return MCDisassembler::Success;
case 107: RegID = getMCReg(VCC_HI, STI); return MCDisassembler::Success;
// ToDo: no support for tba_lo/_hi register
case 108:
case 109: return MCDisassembler::Fail;
// ToDo: no support for tma_lo/_hi register
case 110:
case 111: return MCDisassembler::Fail;
// ToDo: no support for ttmp[0:11] register
case 112:
case 113:
case 114:
case 115:
case 116:
case 117:
case 118:
case 119:
case 120:
case 121:
case 122:
case 123: return MCDisassembler::Fail;
case 124: RegID = getMCReg(M0, STI); return MCDisassembler::Success;
case 126: RegID = getMCReg(EXEC_LO, STI); return MCDisassembler::Success;
case 127: RegID = getMCReg(EXEC_HI, STI); return MCDisassembler::Success;
// ToDo: no support for vccz register
case 251: return MCDisassembler::Fail;
// ToDo: no support for execz register
case 252: return MCDisassembler::Fail;
case 253: RegID = getMCReg(SCC, STI); return MCDisassembler::Success;
default: return MCDisassembler::Fail;
}
}
return MCDisassembler::Fail;
}
DecodeStatus AMDGPUDisassembler::DecodeSrc64Register(unsigned Val,
unsigned &RegID) const {
// ToDo: deal with out-of range registers
using namespace AMDGPU;
if (Val <= 101) {
return DecodeSgprRegister(Val, RegID, 64);
} else if ((Val >= 256) && (Val <= 511)) {
return DecodeVgprRegister(Val - 256, RegID, 64);
} else {
switch(Val) {
case 102: RegID = getMCReg(FLAT_SCR, STI); return MCDisassembler::Success;
case 106: RegID = getMCReg(VCC, STI); return MCDisassembler::Success;
case 126: RegID = getMCReg(EXEC, STI); return MCDisassembler::Success;
default: return MCDisassembler::Fail;
}
}
return MCDisassembler::Fail;
}
DecodeStatus AMDGPUDisassembler::DecodeLiteralConstant(MCInst &Inst,
uint64_t &Literal) const {
// For now all literal constants are supposed to be unsigned integer
// ToDo: deal with signed/unsigned 64-bit integer constants
// ToDo: deal with float/double constants
if (Bytes.size() < 8) {
return MCDisassembler::Fail;
}
Literal =
0 | (Bytes[7] << 24) | (Bytes[6] << 16) | (Bytes[5] << 8) | (Bytes[4] << 0);
return MCDisassembler::Success;
}
DecodeStatus AMDGPUDisassembler::DecodeVGPR_32RegisterClass(llvm::MCInst &Inst,
unsigned Imm,
uint64_t Addr) const {
unsigned RegID;
if (DecodeVgprRegister(Imm, RegID) == MCDisassembler::Success) {
Inst.addOperand(MCOperand::createReg(RegID));
return MCDisassembler::Success;
}
return MCDisassembler::Fail;
}
DecodeStatus AMDGPUDisassembler::DecodeVSRegisterClass(MCInst &Inst,
unsigned Imm,
uint64_t Addr,
bool Is32) const {
// ToDo: different opcodes allow different formats of this operands
if ((Imm >= 128) && (Imm <= 208)) {
// immediate integer
int64_t Val;
if (DecodeImmedInteger(Imm, Val) == MCDisassembler::Success) {
Inst.addOperand(MCOperand::createImm(Val));
return MCDisassembler::Success;
}
} else if ((Imm >= 240) && (Imm <= 248)) {
// immediate float/double
uint64_t Val;
DecodeStatus status;
if (Is32) {
uint32_t Val32;
status = DecodeImmedFloat(Imm, Val32);
Val = static_cast<uint64_t>(Val32);
} else {
status = DecodeImmedDouble(Imm, Val);
}
if (status == MCDisassembler::Success) {
Inst.addOperand(MCOperand::createImm(Val));
return MCDisassembler::Success;
}
} else if (Imm == 254) {
// LDS direct
// ToDo: implement LDS direct read
} else if (Imm == 255) {
// literal constant
HasLiteral = true;
uint64_t Literal;
if (DecodeLiteralConstant(Inst, Literal) == MCDisassembler::Success) {
Inst.addOperand(MCOperand::createImm(Literal));
return MCDisassembler::Success;
}
return MCDisassembler::Fail;
} else if ((Imm == 125) ||
((Imm >= 209) && (Imm <= 239)) ||
(Imm == 249) ||
(Imm == 250) ||
(Imm >= 512)) {
// reserved
return MCDisassembler::Fail;
} else {
// register
unsigned RegID;
DecodeStatus status = Is32 ? DecodeSrc32Register(Imm, RegID)
: DecodeSrc64Register(Imm, RegID);
if (status == MCDisassembler::Success) {
Inst.addOperand(MCOperand::createReg(RegID));
return MCDisassembler::Success;
}
}
return MCDisassembler::Fail;
}
DecodeStatus AMDGPUDisassembler::DecodeVS_32RegisterClass(MCInst &Inst,
unsigned Imm,
uint64_t Addr) const {
return DecodeVSRegisterClass(Inst, Imm, Addr, true);
}
DecodeStatus AMDGPUDisassembler::DecodeVS_64RegisterClass(MCInst &Inst,
unsigned Imm,
uint64_t Addr) const {
return DecodeVSRegisterClass(Inst, Imm, Addr, false);
}
DecodeStatus AMDGPUDisassembler::DecodeVReg_64RegisterClass(llvm::MCInst &Inst,
unsigned Imm,
uint64_t Addr) const {
unsigned RegID;
if (DecodeVgprRegister(Imm, RegID, 64) == MCDisassembler::Success) {
Inst.addOperand(MCOperand::createReg(RegID));
return MCDisassembler::Success;
}
return MCDisassembler::Fail;
}
static MCDisassembler *createAMDGPUDisassembler(const Target &T,
const MCSubtargetInfo &STI,
MCContext &Ctx) {
return new AMDGPUDisassembler(STI, Ctx);
}
extern "C" void LLVMInitializeAMDGPUDisassembler() {
TargetRegistry::RegisterMCDisassembler(TheGCNTarget, createAMDGPUDisassembler);
}