valida-xyz/valida-compiler

Add disassembler support

Closed this issue · 2 comments

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

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.

Closed with 8228002