//===-- 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(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(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(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(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 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(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); }