[llvm] 71199af - [Xtensa 9/10] Add basic support of Xtensa disassembler
via llvm-commits
llvm-commits at lists.llvm.org
Mon Dec 26 04:39:01 PST 2022
Author: Andrei Safronov
Date: 2022-12-26T13:30:51+01:00
New Revision: 71199af14c578a72a5c0fec6ecaa5eab1645a7b7
URL: https://github.com/llvm/llvm-project/commit/71199af14c578a72a5c0fec6ecaa5eab1645a7b7
DIFF: https://github.com/llvm/llvm-project/commit/71199af14c578a72a5c0fec6ecaa5eab1645a7b7.diff
LOG: [Xtensa 9/10] Add basic support of Xtensa disassembler
Differential Revision: https://reviews.llvm.org/D64835
Added:
llvm/lib/Target/Xtensa/Disassembler/CMakeLists.txt
llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp
Modified:
llvm/lib/Target/Xtensa/CMakeLists.txt
llvm/lib/Target/Xtensa/XtensaOperands.td
Removed:
################################################################################
diff --git a/llvm/lib/Target/Xtensa/CMakeLists.txt b/llvm/lib/Target/Xtensa/CMakeLists.txt
index 62731a2cce34..7192f7392072 100644
--- a/llvm/lib/Target/Xtensa/CMakeLists.txt
+++ b/llvm/lib/Target/Xtensa/CMakeLists.txt
@@ -4,6 +4,7 @@ set(LLVM_TARGET_DEFINITIONS Xtensa.td)
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)
@@ -29,6 +30,7 @@ add_llvm_target(XtensaCodeGen
)
add_subdirectory(AsmParser)
+add_subdirectory(Disassembler)
add_subdirectory(MCTargetDesc)
add_subdirectory(TargetInfo)
diff --git a/llvm/lib/Target/Xtensa/Disassembler/CMakeLists.txt b/llvm/lib/Target/Xtensa/Disassembler/CMakeLists.txt
new file mode 100644
index 000000000000..43f235b7cd31
--- /dev/null
+++ b/llvm/lib/Target/Xtensa/Disassembler/CMakeLists.txt
@@ -0,0 +1,11 @@
+add_llvm_component_library(LLVMXtensaDisassembler
+ XtensaDisassembler.cpp
+
+ LINK_COMPONENTS
+ MCDisassembler
+ Support
+ XtensaInfo
+
+ ADD_TO_COMPONENT
+ Xtensa
+ )
diff --git a/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp b/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp
new file mode 100644
index 000000000000..dfa677789d1a
--- /dev/null
+++ b/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp
@@ -0,0 +1,207 @@
+//===-- XtensaDisassembler.cpp - Disassembler for Xtensa ------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the XtensaDisassembler class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MCTargetDesc/XtensaMCTargetDesc.h"
+#include "TargetInfo/XtensaTargetInfo.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCDecoderOps.h"
+#include "llvm/MC/MCDisassembler/MCDisassembler.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/MC/TargetRegistry.h"
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "Xtensa-disassembler"
+
+using DecodeStatus = MCDisassembler::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<uint8_t> Bytes, uint64_t Address,
+ 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" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeXtensaDisassembler() {
+ TargetRegistry::RegisterMCDisassembler(getTheXtensaTarget(),
+ 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 >= std::size(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 < std::size(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<5>(Imm) && "Invalid immediate");
+ Inst.addOperand(MCOperand::createImm(32 - 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;
+}
+
+/// Read three bytes from the ArrayRef and return 24 bit data
+static DecodeStatus readInstruction24(ArrayRef<uint8_t> 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) {
+ report_fatal_error("Big-endian mode currently is not supported!");
+ } else {
+ Insn = (Bytes[2] << 16) | (Bytes[1] << 8) | (Bytes[0] << 0);
+ }
+
+ Size = 3;
+ return MCDisassembler::Success;
+}
+
+#include "XtensaGenDisassemblerTables.inc"
+
+DecodeStatus XtensaDisassembler::getInstruction(MCInst &MI, uint64_t &Size,
+ ArrayRef<uint8_t> Bytes,
+ uint64_t Address,
+ raw_ostream &CS) const {
+ uint32_t Insn;
+ DecodeStatus 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);
+ return Result;
+}
diff --git a/llvm/lib/Target/Xtensa/XtensaOperands.td b/llvm/lib/Target/Xtensa/XtensaOperands.td
index c8fca6f5e7bf..3f73f91fe16e 100644
--- a/llvm/lib/Target/Xtensa/XtensaOperands.td
+++ b/llvm/lib/Target/Xtensa/XtensaOperands.td
@@ -25,6 +25,7 @@ class Immediate<ValueType vt, code pred, string asmop>
def Imm8_AsmOperand : ImmAsmOperand<"Imm8">;
def imm8 : Immediate<i32, [{ return Imm >= -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<i32, [{ return Imm >= -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<i32, [{ return Imm >= -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<i32, [{ return Imm >= -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<i32, [{ return Imm >= 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<i32, [{ return Imm >= 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<i32, [{ return Imm >= 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<i32, [{ return Imm >= 1 && Imm <= 31; }], "Shimm1_31_AsmOperand"> {
let EncoderMethod = "getShimm1_31OpValue";
+ let DecoderMethod = "decodeShimm1_31Operand";
}
// Memory offset 0..255 for 8-bit memory accesses
@@ -105,13 +113,21 @@ class mem<Operand offset> : Operand<i32> {
let PrintMethod = "printMemOperand";
}
-def mem8 : mem<offset8m8>;
+def mem8 : mem<offset8m8> {
+ let DecoderMethod = "decodeMem8Operand";
+}
-def mem16 : mem<offset8m16>;
+def mem16 : mem<offset8m16> {
+ let DecoderMethod = "decodeMem16Operand";
+}
-def mem32 : mem<offset8m32>;
+def mem32 : mem<offset8m32> {
+ let DecoderMethod = "decodeMem32Operand";
+}
-def mem32n : mem<offset4m32>;
+def mem32n : mem<offset4m32> {
+ let DecoderMethod = "decodeMem32nOperand";
+}
//Add patterns for future use in stack addressing mode
def addr_ish1 : ComplexPattern<iPTR, 2, "selectMemRegAddrISH1", [frameindex]>;
More information about the llvm-commits
mailing list