Index: llvm/lib/Target/Xtensa/CMakeLists.txt =================================================================== --- llvm/lib/Target/Xtensa/CMakeLists.txt +++ llvm/lib/Target/Xtensa/CMakeLists.txt @@ -2,6 +2,7 @@ tablegen(LLVM XtensaGenAsmMatcher.inc -gen-asm-matcher) tablegen(LLVM XtensaGenAsmWriter.inc -gen-asm-writer) +tablegen(LLVM XtensaGenDisassemblerTables.inc -gen-disassembler) tablegen(LLVM XtensaGenInstrInfo.inc -gen-instr-info) tablegen(LLVM XtensaGenMCCodeEmitter.inc -gen-emitter) tablegen(LLVM XtensaGenRegisterInfo.inc -gen-register-info) @@ -14,6 +15,7 @@ ) add_subdirectory(AsmParser) +add_subdirectory(Disassembler) add_subdirectory(MCTargetDesc) add_subdirectory(TargetInfo) Index: llvm/lib/Target/Xtensa/Disassembler/CMakeLists.txt =================================================================== --- /dev/null +++ llvm/lib/Target/Xtensa/Disassembler/CMakeLists.txt @@ -0,0 +1,3 @@ +add_llvm_library(LLVMXtensaDisassembler + XtensaDisassembler.cpp + ) Index: llvm/lib/Target/Xtensa/Disassembler/LLVMBuild.txt =================================================================== --- /dev/null +++ llvm/lib/Target/Xtensa/Disassembler/LLVMBuild.txt @@ -0,0 +1,23 @@ +;===-- ./lib/Target/Xtensa/Disassembler/LLVMBuild.txt ---------*- Conf -*--===; +; +; The LLVM Compiler Infrastructure +; +; This file is distributed under the University of Illinois Open Source +; License. See LICENSE.TXT for details. +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[component_0] +type = Library +name = XtensaDisassembler +parent = Xtensa +required_libraries = MC MCDisassembler Support XtensaDesc XtensaInfo +add_to_library_groups = Xtensa Index: llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp =================================================================== --- /dev/null +++ llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp @@ -0,0 +1,269 @@ +//===-- XtensaDisassembler.cpp - Disassembler for Xtensa ------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the XtensaDisassembler class. +// +//===----------------------------------------------------------------------===// + +#include "MCTargetDesc/XtensaMCTargetDesc.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCDisassembler/MCDisassembler.h" +#include "llvm/MC/MCFixedLenDisassembler.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/TargetRegistry.h" + +using namespace llvm; + +#define DEBUG_TYPE "Xtensa-disassembler" + +typedef MCDisassembler::DecodeStatus DecodeStatus; + +namespace { + +class XtensaDisassembler : public MCDisassembler { + bool IsLittleEndian; + +public: + XtensaDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx, bool isLE) + : MCDisassembler(STI, Ctx), IsLittleEndian(isLE) {} + + bool hasDensity() const { + return STI.getFeatureBits()[Xtensa::FeatureDensity]; + } + + DecodeStatus getInstruction(MCInst &Instr, uint64_t &Size, + ArrayRef Bytes, uint64_t Address, + raw_ostream &VStream, + raw_ostream &CStream) const override; +}; +} // end anonymous namespace + +static MCDisassembler *createXtensaDisassembler(const Target &T, + const MCSubtargetInfo &STI, + MCContext &Ctx) { + return new XtensaDisassembler(STI, Ctx, true); +} + +extern "C" void LLVMInitializeXtensaDisassembler() { + TargetRegistry::RegisterMCDisassembler(TheXtensaTarget, + createXtensaDisassembler); +} + +static const unsigned ARDecoderTable[] = { + Xtensa::A0, Xtensa::SP, Xtensa::A2, Xtensa::A3, Xtensa::A4, Xtensa::A5, + Xtensa::A6, Xtensa::A7, Xtensa::A8, Xtensa::A9, Xtensa::A10, Xtensa::A11, + Xtensa::A12, Xtensa::A13, Xtensa::A14, Xtensa::A15}; + +static DecodeStatus DecodeARRegisterClass(MCInst &Inst, uint64_t RegNo, + uint64_t Address, + const void *Decoder) { + if (RegNo > sizeof(ARDecoderTable)) + return MCDisassembler::Fail; + + unsigned Reg = ARDecoderTable[RegNo]; + Inst.addOperand(MCOperand::createReg(Reg)); + return MCDisassembler::Success; +} + +static const unsigned SRDecoderTable[] = {Xtensa::SAR, 3}; + +static DecodeStatus DecodeSRRegisterClass(MCInst &Inst, uint64_t RegNo, + uint64_t Address, + const void *Decoder) { + if (RegNo > 255) + return MCDisassembler::Fail; + + for (unsigned i = 0; i < sizeof(SRDecoderTable); i += 2) { + if (SRDecoderTable[i + 1] == RegNo) { + unsigned Reg = SRDecoderTable[i]; + Inst.addOperand(MCOperand::createReg(Reg)); + return MCDisassembler::Success; + } + } + + return MCDisassembler::Fail; +} + +static DecodeStatus decodeImm8Operand(MCInst &Inst, uint64_t Imm, + int64_t Address, const void *Decoder) { + assert(isUInt<8>(Imm) && "Invalid immediate"); + Inst.addOperand(MCOperand::createImm(SignExtend64<8>(Imm))); + return MCDisassembler::Success; +} + +static DecodeStatus decodeImm8_sh8Operand(MCInst &Inst, uint64_t Imm, + int64_t Address, + const void *Decoder) { + assert(isUInt<8>(Imm) && "Invalid immediate"); + Inst.addOperand(MCOperand::createImm(SignExtend64<16>(Imm << 8))); + return MCDisassembler::Success; +} + +static DecodeStatus decodeImm12Operand(MCInst &Inst, uint64_t Imm, + int64_t Address, const void *Decoder) { + assert(isUInt<12>(Imm) && "Invalid immediate"); + Inst.addOperand(MCOperand::createImm(SignExtend64<12>(Imm))); + return MCDisassembler::Success; +} + +static DecodeStatus decodeUimm4Operand(MCInst &Inst, uint64_t Imm, + int64_t Address, const void *Decoder) { + assert(isUInt<4>(Imm) && "Invalid immediate"); + Inst.addOperand(MCOperand::createImm(Imm)); + return MCDisassembler::Success; +} + +static DecodeStatus decodeUimm5Operand(MCInst &Inst, uint64_t Imm, + int64_t Address, const void *Decoder) { + assert(isUInt<5>(Imm) && "Invalid immediate"); + Inst.addOperand(MCOperand::createImm(Imm)); + return MCDisassembler::Success; +} + +static DecodeStatus decodeImm1_16Operand(MCInst &Inst, uint64_t Imm, + int64_t Address, const void *Decoder) { + assert(isUInt<4>(Imm) && "Invalid immediate"); + Inst.addOperand(MCOperand::createImm(Imm + 1)); + return MCDisassembler::Success; +} + +static DecodeStatus decodeShimm1_31Operand(MCInst &Inst, uint64_t Imm, + int64_t Address, + const void *Decoder) { + assert(isUInt<4>(Imm) && "Invalid immediate"); + Inst.addOperand(MCOperand::createImm(32 - Imm)); + return MCDisassembler::Success; +} + +static int64_t TableB4const[16] = {-1, 1, 2, 3, 4, 5, 6, 7, + 8, 10, 12, 16, 32, 64, 128, 256}; +static DecodeStatus decodeB4constOperand(MCInst &Inst, uint64_t Imm, + int64_t Address, const void *Decoder) { + assert(isUInt<4>(Imm) && "Invalid immediate"); + + Inst.addOperand(MCOperand::createImm(TableB4const[Imm])); + return MCDisassembler::Success; +} + +static int64_t TableB4constu[16] = {32768, 65536, 2, 3, 4, 5, 6, 7, + 8, 10, 12, 16, 32, 64, 128, 256}; +static DecodeStatus decodeB4constuOperand(MCInst &Inst, uint64_t Imm, + int64_t Address, + const void *Decoder) { + assert(isUInt<4>(Imm) && "Invalid immediate"); + + Inst.addOperand(MCOperand::createImm(TableB4constu[Imm])); + return MCDisassembler::Success; +} + +static DecodeStatus decodeMem8Operand(MCInst &Inst, uint64_t Imm, + int64_t Address, const void *Decoder) { + assert(isUInt<12>(Imm) && "Invalid immediate"); + DecodeARRegisterClass(Inst, Imm & 0xf, Address, Decoder); + Inst.addOperand(MCOperand::createImm((Imm >> 4) & 0xff)); + return MCDisassembler::Success; +} + +static DecodeStatus decodeMem16Operand(MCInst &Inst, uint64_t Imm, + int64_t Address, const void *Decoder) { + assert(isUInt<12>(Imm) && "Invalid immediate"); + DecodeARRegisterClass(Inst, Imm & 0xf, Address, Decoder); + Inst.addOperand(MCOperand::createImm((Imm >> 3) & 0x1fe)); + return MCDisassembler::Success; +} + +static DecodeStatus decodeMem32Operand(MCInst &Inst, uint64_t Imm, + int64_t Address, const void *Decoder) { + assert(isUInt<12>(Imm) && "Invalid immediate"); + DecodeARRegisterClass(Inst, Imm & 0xf, Address, Decoder); + Inst.addOperand(MCOperand::createImm((Imm >> 2) & 0x3fc)); + return MCDisassembler::Success; +} + +static DecodeStatus decodeMem32nOperand(MCInst &Inst, uint64_t Imm, + int64_t Address, const void *Decoder) { + assert(isUInt<8>(Imm) && "Invalid immediate"); + DecodeARRegisterClass(Inst, Imm & 0xf, Address, Decoder); + Inst.addOperand(MCOperand::createImm((Imm >> 2) & 0x3c)); + return MCDisassembler::Success; +} + +/// Read two bytes from the ArrayRef and return 16 bit data sorted +/// according to the given endianness. +static DecodeStatus readInstruction16(ArrayRef Bytes, uint64_t Address, + uint64_t &Size, uint32_t &Insn, + bool IsLittleEndian) { + // We want to read exactly 2 Bytes of data. + if (Bytes.size() < 2) { + Size = 0; + return MCDisassembler::Fail; + } + + if (!IsLittleEndian) { + llvm_unreachable("Big-endian mode currently is not supported!"); + } else { + Insn = (Bytes[1] << 8) | Bytes[0]; + } + + return MCDisassembler::Success; +} + +/// Read four bytes from the ArrayRef and return 24 bit data sorted +/// according to the given endianness. +static DecodeStatus readInstruction24(ArrayRef Bytes, uint64_t Address, + uint64_t &Size, uint32_t &Insn, + bool IsLittleEndian) { + // We want to read exactly 3 Bytes of data. + if (Bytes.size() < 3) { + Size = 0; + return MCDisassembler::Fail; + } + + if (!IsLittleEndian) { + llvm_unreachable("Big-endian mode currently is not supported!"); + } else { + Insn = (Bytes[2] << 16) | (Bytes[1] << 8) | (Bytes[0] << 0); + } + + return MCDisassembler::Success; +} + +#include "XtensaGenDisassemblerTables.inc" + +DecodeStatus XtensaDisassembler::getInstruction(MCInst &MI, uint64_t &Size, + ArrayRef Bytes, + uint64_t Address, + raw_ostream &OS, + raw_ostream &CS) const { + uint32_t Insn; + DecodeStatus Result; + + if (hasDensity()) { + Result = readInstruction16(Bytes, Address, Size, Insn, IsLittleEndian); + if (Result == MCDisassembler::Fail) + return MCDisassembler::Fail; + LLVM_DEBUG(dbgs() << "Trying Xtensa 16-bit instruction table :\n"); + Result = decodeInstruction(DecoderTable16, MI, Insn, Address, this, STI); + if (Result != MCDisassembler::Fail) { + Size = 2; + return Result; + } + } + + Result = readInstruction24(Bytes, Address, Size, Insn, IsLittleEndian); + if (Result == MCDisassembler::Fail) + return MCDisassembler::Fail; + LLVM_DEBUG(dbgs() << "Trying Xtensa 24-bit instruction table :\n"); + Result = decodeInstruction(DecoderTable24, MI, Insn, Address, this, STI); + Size = 3; + return Result; +} Index: llvm/lib/Target/Xtensa/LLVMBuild.txt =================================================================== --- llvm/lib/Target/Xtensa/LLVMBuild.txt +++ llvm/lib/Target/Xtensa/LLVMBuild.txt @@ -1,5 +1,5 @@ [common] -subdirectories = AsmParser TargetInfo MCTargetDesc +subdirectories = AsmParser Disassembler TargetInfo MCTargetDesc [component_0] type = TargetGroup @@ -7,6 +7,7 @@ parent = Target has_asmparser = 1 has_asmprinter = 1 +has_disassembler = 1 [component_1] type = Library Index: llvm/lib/Target/Xtensa/XtensaOperands.td =================================================================== --- llvm/lib/Target/Xtensa/XtensaOperands.td +++ llvm/lib/Target/Xtensa/XtensaOperands.td @@ -26,6 +26,7 @@ def Imm8_AsmOperand: ImmAsmOperand<"Imm8">; def imm8: Immediate= -128 && Imm <= 127; }], "Imm8_AsmOperand"> { let EncoderMethod = "getImm8OpValue"; + let DecoderMethod = "decodeImm8Operand"; } // imm8_sh8 predicate - Immediate in the range [-32768,32512] with (bits[7-0] == 0) @@ -33,42 +34,49 @@ def Imm8_sh8_AsmOperand: ImmAsmOperand<"Imm8_sh8">; def imm8_sh8: Immediate= -32768 && Imm <= 32512 && ((Imm & 0xFF) == 0); }], "Imm8_sh8_AsmOperand"> { let EncoderMethod = "getImm8_sh8OpValue"; + let DecoderMethod = "decodeImm8_sh8Operand"; } // imm12 predicate - Immediate in the range [-2048,2047] def Imm12_AsmOperand: ImmAsmOperand<"Imm12">; def imm12: Immediate= -2048 && Imm <= 2047; }], "Imm12_AsmOperand"> { let EncoderMethod = "getImm12OpValue"; + let DecoderMethod = "decodeImm12Operand"; } // imm12m predicate - Immediate for MOV operation def Imm12m_AsmOperand: ImmAsmOperand<"Imm12m">; def imm12m: Immediate= -2048 && Imm <= 2047; }], "Imm12m_AsmOperand"> { let EncoderMethod = "getImm12OpValue"; + let DecoderMethod = "decodeImm12Operand"; } // uimm4 predicate - Immediate in the range [0,15] def Uimm4_AsmOperand: ImmAsmOperand<"Uimm4">; def uimm4: Immediate= 0 && Imm <= 15; }], "Uimm4_AsmOperand"> { let EncoderMethod = "getUimm4OpValue"; + let DecoderMethod = "decodeUimm4Operand"; } // uimm5 predicate - Immediate in the range [0,31] def Uimm5_AsmOperand: ImmAsmOperand<"Uimm5">; def uimm5: Immediate= 0 && Imm <= 31; }], "Uimm5_AsmOperand"> { let EncoderMethod = "getUimm5OpValue"; + let DecoderMethod = "decodeUimm5Operand"; } // imm1_16 predicate - Immediate in the range [1,16] def Imm1_16_AsmOperand: ImmAsmOperand<"Imm1_16">; def imm1_16: Immediate= 1 && Imm <= 16; }], "Imm1_16_AsmOperand"> { let EncoderMethod = "getImm1_16OpValue"; + let DecoderMethod = "decodeImm1_16Operand"; } // shimm1_31 predicate - Immediate in the range [1,31] def Shimm1_31_AsmOperand: ImmAsmOperand<"Shimm1_31">; def shimm1_31: Immediate= 1 && Imm <= 31; }], "Shimm1_31_AsmOperand"> { let EncoderMethod = "getShimm1_31OpValue"; + let DecoderMethod = "decodeShimm1_31Operand"; } // Memory offset 0..255 for 8-bit memory accesses @@ -108,6 +116,7 @@ }], "B4const_AsmOperand"> { let EncoderMethod = "getB4constOpValue"; + let DecoderMethod = "decodeB4constOperand"; } // b4constu predicate - Branch Immediate 4-bit unsigned operand @@ -123,6 +132,7 @@ }], "B4constu_AsmOperand"> { let EncoderMethod = "getB4constuOpValue"; + let DecoderMethod = "decodeB4constuOperand"; } //===----------------------------------------------------------------------===// // Memory address operands @@ -136,13 +146,25 @@ let PrintMethod = "printMemOperand"; } -def mem8: mem; +def mem8: mem +{ + let DecoderMethod = "decodeMem8Operand"; +} -def mem16: mem; +def mem16: mem +{ + let DecoderMethod = "decodeMem16Operand"; +} -def mem32: mem; +def mem32: mem +{ + let DecoderMethod = "decodeMem32Operand"; +} -def mem32n: mem; +def mem32n: mem +{ + let DecoderMethod = "decodeMem32nOperand"; +} //Add patterns for future use in stack addressing mode def addr_ish1: ComplexPattern;