Add disassembler support
Closed this issue · 2 comments
0x59616e commented
I was informed that I don't have write access, so I paste my patch here instead of using PR.
This patch adds disassembler support. Although I haven't done a comprehensive test, I believe all of the instructions can be disassembled correctly.
cc @maxgillett
diff --git a/llvm/lib/Target/Delendum/DelendumInstrFormats.td b/llvm/lib/Target/Delendum/DelendumInstrFormats.td
index a78d995188ad..bf8bb74b7551 100644
--- a/llvm/lib/Target/Delendum/DelendumInstrFormats.td
+++ b/llvm/lib/Target/Delendum/DelendumInstrFormats.td
@@ -15,7 +15,7 @@ class DInst<bits<32> op, dag outs, dag ins, string asmstr, list<dag> pattern>
let AsmString = asmstr;
let Pattern = pattern;
- field bits<32> SoftFail = 0;
+ // field bits<32> SoftFail = 0;
}
class DPseudoInst<bits<32> op, dag outs, dag ins, string asmstr, list<dag> pattern>
diff --git a/llvm/lib/Target/Delendum/DelendumInstrInfo.td b/llvm/lib/Target/Delendum/DelendumInstrInfo.td
index 739eadd5c1db..89545cd8c3f0 100644
--- a/llvm/lib/Target/Delendum/DelendumInstrInfo.td
+++ b/llvm/lib/Target/Delendum/DelendumInstrInfo.td
@@ -23,12 +23,16 @@ def callseq_end : SDNode<"ISD::CALLSEQ_END", SDT_DCallSeqEnd,
// multiple operand types here, and check whether a given operand needs to be
// split into smaller ones.
def ImmOp32 : Operand<i32> {
- let DecoderMethod = "DecodeImm32";
+ let DecoderMethod = "DecodeImmOp32";
}
def MemOp : Operand<iPTR> {
let PrintMethod = "printMemOperand";
- let MIOperandInfo = (ops GPR, ImmOp32);
+ let MIOperandInfo = (ops GPR:$reg, ImmOp32:$imm);
+}
+
+class MemOpEncoding<string opname> {
+ dag Value = (ascend (operand "$"#opname#".reg", 32), (operand "$"#opname#".imm", 32));
}
// Node immediate fits as 32-bit sign extended on target immediate.
@@ -58,23 +62,23 @@ def addr : ComplexPattern<iPTR, 2, "SelectAddr", [frameindex], [SDNPWantParent]>
class ALU_rr<bits<32> op, string opcodestr, SDNode OpNode>
: DInst<op, (outs GPR:$rd), (ins MemOp:$rs1, MemOp:$rs2),
- !strconcat(opcodestr, "$rd, $rs1, $rs2"),
+ opcodestr#"\t$rd, $rs1, $rs2",
[(set GPR:$rd, (OpNode addr:$rs1, addr:$rs2))]> {
// TODO: How can we prepend 'op' using a DAG operator?
- let Inst = (ascend
+ let Inst = (ascend op,
(operand "$rd", 32),
- (operand "$rs1", 32),
- (operand "$rs2", 32));
+ MemOpEncoding<"rs1">.Value,
+ MemOpEncoding<"rs2">.Value);
}
class ALU_ri<bits<32> op, string opcodestr, SDNode OpNode,
Operand Od, PatLeaf imm_type>
: DInst<op, (outs GPR:$rd), (ins MemOp:$rs1, Od:$imm32),
- !strconcat(opcodestr, "$rd, $rs1, $imm32"),
+ !strconcat(opcodestr, "\t$rd, $rs1, $imm32"),
[(set GPR:$rd, (OpNode addr:$rs1, imm_type:$imm32))]> {
- let Inst = (ascend
+ let Inst = (ascend op,
(operand "$rd", 32),
- (operand "$rs1", 32),
+ MemOpEncoding<"rs1">.Value,
(operand "$imm32", 32));
}
@@ -82,18 +86,18 @@ class LOAD<bits<32> op, string instr_asm, PatFrag OpNode>
: DInst<op, (outs GPR:$ra), (ins MemOp:$addr),
!strconcat(instr_asm, "\t$ra, $addr"),
[(set GPR:$ra, (OpNode addr:$addr))]> {
- let Inst = (ascend
+ let Inst = (ascend op,
(operand "$ra", 32),
- (operand "$addr", 32));
+ MemOpEncoding<"addr">.Value);
}
class STORE<bits<32> op, string instr_asm, PatFrag OpNode>
: DInst<op, (outs), (ins MemOp:$ra, MemOp:$addr),
!strconcat(instr_asm, "\t$ra, $addr"),
[(OpNode addr:$ra, addr:$addr)]> {
- let Inst = (ascend
- (operand "$ra", 32),
- (operand "$addr", 32));
+ let Inst = (ascend op,
+ MemOpEncoding<"ra">.Value,
+ MemOpEncoding<"addr">.Value);
}
//===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/Delendum/Disassembler/DelendumDisassembler.cpp b/llvm/lib/Target/Delendum/Disassembler/DelendumDisassembler.cpp
index d56ff475931d..85e9aac402e6 100644
--- a/llvm/lib/Target/Delendum/Disassembler/DelendumDisassembler.cpp
+++ b/llvm/lib/Target/Delendum/Disassembler/DelendumDisassembler.cpp
@@ -32,9 +32,20 @@ using namespace llvm;
typedef MCDisassembler::DecodeStatus DecodeStatus;
-static DecodeStatus DecodeImm32(MCInst &Inst, uint64_t Imm, uint64_t Address,
- const void *Decoder) {
- // TODO
+static DecodeStatus DecodeImmOp32(MCInst &Inst, uint64_t Imm, uint64_t Address,
+ const void *Decoder) {
+ Inst.addOperand(MCOperand::createImm(Imm));
+ return DecodeStatus::Success;
+}
+
+static DecodeStatus DecodeGPRRegisterClass(MCInst &Inst, uint64_t RegNo,
+ uint64_t Address,
+ const void *Decoder) {
+ if (RegNo >= 4)
+ return DecodeStatus::Fail;
+ static unsigned GPRList[] = {DL::PC, DL::SP, DL::FP, DL::X0};
+ Inst.addOperand(MCOperand::createReg(GPRList[RegNo]));
+ return DecodeStatus::Success;
}
#include "DelendumGenDisassemblerTable.inc"
@@ -55,7 +66,28 @@ DecodeStatus DelendumDisassembler::getInstruction(MCInst &Instr, uint64_t &Size,
uint64_t Address,
raw_ostream &CStream) const {
DecodeStatus Result;
- // TODO
+ auto MakeUp = [&](APInt &Insn, unsigned InstrBits) {
+ unsigned Idx = Insn.getBitWidth() >> 3;
+ unsigned RoundUp = alignTo(InstrBits, Align(32));
+ if (RoundUp > Insn.getBitWidth())
+ Insn = Insn.zext(RoundUp);
+ RoundUp = RoundUp >> 3;
+ for (; Idx < RoundUp; Idx += 4) {
+ Insn.insertBits(support::endian::read32be(&Bytes[Idx]), Idx * 8, 32);
+ }
+ };
+
+ APInt Insn(32, support::endian::read32be(Bytes.data()));
+ // 4 bytes of data are consumed, so set Size to 4
+ // If we don't do this, disassembler may generate result even
+ // the encoding is invalid. We need to let it fail correctly.
+ Size = 4;
+ Result = decodeInstruction(DecoderTableDelendum192, Instr, Insn, Address,
+ this, STI, MakeUp);
+ if (Result == DecodeStatus::Success)
+ Size = InstrLenTable[Instr.getOpcode()] >> 3;
+
+ LLVM_DEBUG(llvm::dbgs() << "Disassemble: "; Instr.dump());
return Result;
}
diff --git a/llvm/lib/Target/Delendum/MCTargetDesc/DelendumInstPrinter.cpp b/llvm/lib/Target/Delendum/MCTargetDesc/DelendumInstPrinter.cpp
index 9d24a5b64e53..38b1907a33b2 100644
--- a/llvm/lib/Target/Delendum/MCTargetDesc/DelendumInstPrinter.cpp
+++ b/llvm/lib/Target/Delendum/MCTargetDesc/DelendumInstPrinter.cpp
@@ -50,23 +50,31 @@ void DelendumInstPrinter::printInst(const MCInst *MI, uint64_t Address,
bool DelendumInstPrinter::printDelendumAliasInstr(const MCInst *MI,
raw_ostream &O) {
- // TODO
- return true;
+ return false;
}
void DelendumInstPrinter::printOperand(const MCInst *MI, int opNum,
raw_ostream &O) {
- // TODO
+ MCOperand Op = MI->getOperand(opNum);
+ if (Op.isReg())
+ O << "%" << getRegisterName(Op.getReg());
+ else if (Op.isImm())
+ O << "#" << Op.getImm();
}
void DelendumInstPrinter::printMemOperand(const MCInst *MI, int opNum,
- raw_ostream &O, const char *Modifier) {
- // TODO
+ raw_ostream &O,
+ const char *Modifier) {
+ O << "(";
+ printOperand(MI, opNum, O);
+ O << ", ";
+ printOperand(MI, opNum + 1, O);
+ O << ")";
}
void DelendumInstPrinter::printCCOperand(const MCInst *MI, int opNum,
raw_ostream &O) {
- // TODO
+ llvm_unreachable("unimplemented");
}
bool DelendumInstPrinter::printGetPCX(const MCInst *MI, unsigned opNum,
diff --git a/llvm/test/MC/Disassembler/Delendum/arith.txt b/llvm/test/MC/Disassembler/Delendum/arith.txt
new file mode 100644
index 000000000000..a0770bc963bc
--- /dev/null
+++ b/llvm/test/MC/Disassembler/Delendum/arith.txt
@@ -0,0 +1,4 @@
+# RUN: llvm-mc -disassemble --triple=delendum %s | FileCheck %s
+
+# CHECK: add %pc, (%pc, #49), (%pc, #19)
+0x00 0x00 0x00 0x03 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x31 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x13
\ No newline at end of file
maxgillett commented
This looks great! Thank you! Are you able to submit this as a PR under the current permissions, or would you prefer to have me merge these changes in?
I'm creating a separate issue now to describe the ISA spec, because I'm not sure that I've implemented it correctly so far with TableGen.
maxgillett commented
Closed with 8228002