[llvm] [TableGen] Emit Debug code for dynamic bits(eg: instruction operands) in DecoderEmitter (PR #194699)

Prerona Chaudhuri via llvm-commits llvm-commits at lists.llvm.org
Wed May 6 13:48:00 PDT 2026


https://github.com/pchaudhuri-nv updated https://github.com/llvm/llvm-project/pull/194699

>From d112846c1afaea7a2588b20d5b9deffa07bc8560 Mon Sep 17 00:00:00 2001
From: pchaudhuri-nv <pchaudhuri at nvidia.com>
Date: Wed, 6 May 2026 16:47:57 +0000
Subject: [PATCH] [TableGen] Emit per-operand decode debug logging via dbgFail
 helpers
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Generated disassembler code now logs FAIL for each operand decode and
whole-instruction decode methods (emitCheckWithDbgMsg). Each emitted
check site is a single
`if (!Check(...)) return dbgFailOpd(...);` (or `dbgFailInsn(...)`) line.

Two specialized helpers, both in the decoder boilerplate:

  - dbgFailOpd(Op, Desc, Decoder, ...)   — for per-operand check sites.
  - dbgFailInsn(Name, Decoder, ...)     — for whole-instruction custom
                                          decoder check sites.

Each helper owns the connector strings (": ", " using ", ": insn using ",
" : FAIL"), so they appear exactly once in .rodata. The call site only
carries the unique values as separate string-literal arguments, and the
linker can naturally dedup the operand names ("dst", "src", "imm", ...),
field descriptions ("field(0,3)", "bits<0>", ...), and decoder-method
names that recur thousands of times across emitted check sites.

Two debug prints that don't carry diagnostic value are dropped: the
PASS-side per-operand log (FAIL is the only message that helps when
chasing a decoder bug) and the per-attempt "attempting to decode
Opcode" log (redundant with the existing post-decode PASS/FAIL line).

Tests:
  - DecoderEmitter and RegClassByHwMode TableGen tests updated.
  - AArch64 MC lit test (aarch64-disassembler-debug.txt) feeds a
    malformed `add (imm)` (with shift = 2; only 0 and 1 are legal) so
    the generated decode table exercises the helpers end-to-end via
    -debug-only=aarch64-disassembler.

Code-bloat measurements from the original single-helper landing
(tables in the prior commit message) predate this dedup refactor and
should be re-measured once we want a current snapshot.

Original work was authored partly via Cursor and partly via Claude;
this squashed commit consolidates both into a single change.

Assisted by Claude.
---
 .../AArch64/aarch64-disassembler-debug.txt    | 16 ++++
 .../TableGen/DecoderEmitter/VarLenDecoder.td  | 10 +-
 .../DecoderEmitter/operand-decoder.td         |  3 +-
 .../DecoderEmitter/trydecode-emission.td      |  3 +-
 .../DecoderEmitter/trydecode-emission2.td     |  6 +-
 .../DecoderEmitter/trydecode-emission3.td     |  4 +-
 .../DecoderEmitter/trydecode-emission4.td     |  3 +-
 llvm/test/TableGen/RegClassByHwMode.td        | 36 ++++++--
 llvm/utils/TableGen/DecoderEmitter.cpp        | 92 ++++++++++++++++---
 9 files changed, 143 insertions(+), 30 deletions(-)
 create mode 100644 llvm/test/MC/Disassembler/AArch64/aarch64-disassembler-debug.txt

diff --git a/llvm/test/MC/Disassembler/AArch64/aarch64-disassembler-debug.txt b/llvm/test/MC/Disassembler/AArch64/aarch64-disassembler-debug.txt
new file mode 100644
index 0000000000000..25aab52f0b945
--- /dev/null
+++ b/llvm/test/MC/Disassembler/AArch64/aarch64-disassembler-debug.txt
@@ -0,0 +1,16 @@
+# REQUIRES: asserts
+# RUN: llvm-mc -triple=aarch64 -mattr=+v8a -disassemble -debug-only=aarch64-disassembler < %s 2>&1 | FileCheck %s
+#
+# Exercises LLVM_DEBUG output from DecoderEmitter for dynamic bits like instruction operand.
+
+# blr x0 — valid; reaches per-operand checks and succeeds.
+# CHECK: OPC_Decode: opcode {{[0-9]+}} using decoder {{[0-9]+}}: PASS, decoding complete
+
+# Malformed `add (imm)` with `shift` field = 2 (only 0 and 1 are legal). The
+# whole-instruction decoder DecodeAddSubImmShift returns Fail, so the generated
+# table emits dbgFailInsn("ADDXri", "DecodeAddSubImmShift").
+# CHECK: OPC_Decode for ADDXri: insn using DecodeAddSubImmShift : FAIL
+# CHECK-NEXT: OPC_Decode: opcode {{[0-9]+}} using decoder {{[0-9]+}}: FAIL, decoding complete
+
+0x0 0x0 0x3f 0xd6
+0xe5 0x98 0x99 0x91
diff --git a/llvm/test/TableGen/DecoderEmitter/VarLenDecoder.td b/llvm/test/TableGen/DecoderEmitter/VarLenDecoder.td
index faac5cba4579f..0540bfc6e38eb 100644
--- a/llvm/test/TableGen/DecoderEmitter/VarLenDecoder.td
+++ b/llvm/test/TableGen/DecoderEmitter/VarLenDecoder.td
@@ -65,17 +65,17 @@ def FOO32 : MyVarInst<MemOp32> {
 
 // CHECK:      case 0:
 // CHECK-NEXT: tmp = fieldFromInstruction(insn, 8, 3);
-// CHECK-NEXT: if (!Check(S, DecodeRegClassRegisterClass(MI, tmp, Address, Decoder))) { return MCDisassembler::Fail; }
+// CHECK-NEXT: if (!Check(S, DecodeRegClassRegisterClass(MI, tmp, Address, Decoder))) return dbgFailOpd("opd", "field(8,3)", "DecodeRegClassRegisterClass");
 // CHECK-NEXT: tmp = fieldFromInstruction(insn, 0, 3);
-// CHECK-NEXT: if (!Check(S, DecodeRegClassRegisterClass(MI, tmp, Address, Decoder))) { return MCDisassembler::Fail; }
+// CHECK-NEXT: if (!Check(S, DecodeRegClassRegisterClass(MI, tmp, Address, Decoder))) return dbgFailOpd("opd", "field(0,3)", "DecodeRegClassRegisterClass");
 // CHECK-NEXT: tmp = fieldFromInstruction(insn, 11, 16);
-// CHECK-NEXT: if (!Check(S, myCustomDecoder(MI, tmp, Address, Decoder))) { return MCDisassembler::Fail; }
+// CHECK-NEXT: if (!Check(S, myCustomDecoder(MI, tmp, Address, Decoder))) return dbgFailOpd("opd", "field(11,16)", "myCustomDecoder");
 // CHECK-NEXT: return S;
 // CHECK-NEXT: case 1:
 // CHECK-NEXT: tmp = fieldFromInstruction(insn, 8, 3);
-// CHECK-NEXT: if (!Check(S, DecodeRegClassRegisterClass(MI, tmp, Address, Decoder))) { return MCDisassembler::Fail; }
+// CHECK-NEXT: if (!Check(S, DecodeRegClassRegisterClass(MI, tmp, Address, Decoder))) return dbgFailOpd("opd", "field(8,3)", "DecodeRegClassRegisterClass");
 // CHECK-NEXT: tmp = fieldFromInstruction(insn, 0, 3);
-// CHECK-NEXT: if (!Check(S, myCustomDecoder(MI, tmp, Address, Decoder))) { return MCDisassembler::Fail; }
+// CHECK-NEXT: if (!Check(S, myCustomDecoder(MI, tmp, Address, Decoder))) return dbgFailOpd("opd", "field(0,3)", "myCustomDecoder");
 // CHECK-NEXT: tmp = 0x0;
 // CHECK-NEXT: tmp |= fieldFromInstruction(insn, 11, 16) << 16;
 // CHECK-NEXT: tmp |= fieldFromInstruction(insn, 27, 16);
diff --git a/llvm/test/TableGen/DecoderEmitter/operand-decoder.td b/llvm/test/TableGen/DecoderEmitter/operand-decoder.td
index c6ec2ee1a4db4..73f9c8e211768 100644
--- a/llvm/test/TableGen/DecoderEmitter/operand-decoder.td
+++ b/llvm/test/TableGen/DecoderEmitter/operand-decoder.td
@@ -12,8 +12,7 @@ def MyTarget : Target {
 }
 
 // CHECK-LABEL: case 0:
-// CHECK-NEXT:    if (!Check(S, DecodeRCRegisterClass(MI, Decoder)))
-// CHECK-NEXT:      return MCDisassembler::Fail;
+// CHECK-NEXT:    if (!Check(S, DecodeRCRegisterClass(MI, Decoder))) return dbgFailOpd("op0", "bits<0>", "DecodeRCRegisterClass");
 // CHECK-NEXT:    tmp = fieldFromInstruction(insn, 2, 4);
 // CHECK-NEXT:    MI.addOperand(MCOperand::createImm(tmp));
 // CHECK-NEXT:    tmp = 0x0;
diff --git a/llvm/test/TableGen/DecoderEmitter/trydecode-emission.td b/llvm/test/TableGen/DecoderEmitter/trydecode-emission.td
index a39f26a6e715a..75aaadce620f9 100644
--- a/llvm/test/TableGen/DecoderEmitter/trydecode-emission.td
+++ b/llvm/test/TableGen/DecoderEmitter/trydecode-emission.td
@@ -43,4 +43,5 @@ def InstB : TestInstruction {
 // CHECK-NEXT:                                 // 14: }
 // CHECK-NEXT: };
 
-// CHECK: if (!Check(S, DecodeInstB(MI, insn, Address, Decoder))) { DecodeComplete = false; return MCDisassembler::Fail; }
+// CHECK-LABEL: case 0:
+// CHECK-NEXT:    if (!Check(S, DecodeInstB(MI, insn, Address, Decoder))) return dbgFailInsn("InstB", "DecodeInstB", &DecodeComplete);
diff --git a/llvm/test/TableGen/DecoderEmitter/trydecode-emission2.td b/llvm/test/TableGen/DecoderEmitter/trydecode-emission2.td
index 40d68061bfc0d..a676bb57104f4 100644
--- a/llvm/test/TableGen/DecoderEmitter/trydecode-emission2.td
+++ b/llvm/test/TableGen/DecoderEmitter/trydecode-emission2.td
@@ -42,5 +42,7 @@ def InstB : TestInstruction {
 // CHECK-NEXT:                                 // 22: }
 // CHECK-NEXT: };
 
-// CHECK: if (!Check(S, DecodeInstB(MI, insn, Address, Decoder))) { DecodeComplete = false; return MCDisassembler::Fail; }
-// CHECK: if (!Check(S, DecodeInstA(MI, insn, Address, Decoder))) { DecodeComplete = false; return MCDisassembler::Fail; }
+// CHECK-LABEL: case 0:
+// CHECK-NEXT:    if (!Check(S, DecodeInstB(MI, insn, Address, Decoder))) return dbgFailInsn("InstB", "DecodeInstB", &DecodeComplete);
+// CHECK-LABEL: case 1:
+// CHECK-NEXT:    if (!Check(S, DecodeInstA(MI, insn, Address, Decoder))) return dbgFailInsn("InstA", "DecodeInstA", &DecodeComplete);
diff --git a/llvm/test/TableGen/DecoderEmitter/trydecode-emission3.td b/llvm/test/TableGen/DecoderEmitter/trydecode-emission3.td
index 2e2d1ddb8b8f6..f7ff58d307087 100644
--- a/llvm/test/TableGen/DecoderEmitter/trydecode-emission3.td
+++ b/llvm/test/TableGen/DecoderEmitter/trydecode-emission3.td
@@ -44,4 +44,6 @@ def InstB : TestInstruction {
 // CHECK-NEXT:                                 // 14: }
 // CHECK-NEXT: };
 
-// CHECK: if (!Check(S, DecodeInstBOp(MI, tmp, Address, Decoder))) { DecodeComplete = false; return MCDisassembler::Fail; }
+// CHECK-LABEL: case 0:
+// CHECK-NEXT:    tmp = fieldFromInstruction(insn, 0, 2);
+// CHECK-NEXT:    if (!Check(S, DecodeInstBOp(MI, tmp, Address, Decoder))) return dbgFailOpd("op", "field(0,2)", "DecodeInstBOp", &DecodeComplete);
diff --git a/llvm/test/TableGen/DecoderEmitter/trydecode-emission4.td b/llvm/test/TableGen/DecoderEmitter/trydecode-emission4.td
index bb0f658a037e8..5b54d70af70ba 100644
--- a/llvm/test/TableGen/DecoderEmitter/trydecode-emission4.td
+++ b/llvm/test/TableGen/DecoderEmitter/trydecode-emission4.td
@@ -42,4 +42,5 @@ def InstB : TestInstruction {
 // CHECK-NEXT:                                  // 16: }
 // CHECK-NEXT: };
 
-// CHECK: if (!Check(S, DecodeInstB(MI, insn, Address, Decoder))) { DecodeComplete = false; return MCDisassembler::Fail; }
+// CHECK-LABEL: case 0:
+// CHECK-NEXT:    if (!Check(S, DecodeInstB(MI, insn, Address, Decoder))) return dbgFailInsn("InstB", "DecodeInstB", &DecodeComplete);
diff --git a/llvm/test/TableGen/RegClassByHwMode.td b/llvm/test/TableGen/RegClassByHwMode.td
index b7484d05e066c..a8a1135dba71f 100644
--- a/llvm/test/TableGen/RegClassByHwMode.td
+++ b/llvm/test/TableGen/RegClassByHwMode.td
@@ -144,6 +144,24 @@ include "Common/RegClassByHwModeCommon.td"
 
 
 
+// DISASM: DecodeStatus dbgFailOpd(const char *Op, const char *Desc, const char *Decoder,
+// DISASM-NEXT:                        bool *DecodeComplete = nullptr) {
+// DISASM-NEXT:   LLVM_DEBUG(dbgs() << "OPC_Decode for " << Op << ": " << Desc << " using "
+// DISASM-NEXT:                     << Decoder << " : FAIL\n");
+// DISASM-NEXT:   if (DecodeComplete)
+// DISASM-NEXT:     *DecodeComplete = false;
+// DISASM-NEXT:   return MCDisassembler::Fail;
+// DISASM-NEXT: }
+// DISASM-EMPTY:
+// DISASM-NEXT: DecodeStatus dbgFailInsn(const char *Name, const char *Decoder,
+// DISASM-NEXT:                          bool *DecodeComplete = nullptr) {
+// DISASM-NEXT:   LLVM_DEBUG(dbgs() << "OPC_Decode for " << Name << ": insn using " << Decoder
+// DISASM-NEXT:                     << " : FAIL\n");
+// DISASM-NEXT:   if (DecodeComplete)
+// DISASM-NEXT:     *DecodeComplete = false;
+// DISASM-NEXT:   return MCDisassembler::Fail;
+// DISASM-NEXT: }
+
 // DISASM{LITERAL}: [[maybe_unused]]
 // DISASM-NEXT: static DecodeStatus DecodeMyPtrRCRegClassByHwMode(MCInst &Inst, unsigned Imm, uint64_t Addr, const MCDisassembler *Decoder) {
 // DISASM-NEXT:   switch (Decoder->getSubtargetInfo().getHwMode(MCSubtargetInfo::HwMode_RegInfo)) {
@@ -185,19 +203,25 @@ include "Common/RegClassByHwModeCommon.td"
 // DISASM: static DecodeStatus decodeToMCInst(
 // DISASM:   switch (Idx) {
 // DISASM: case 0:
-// DISASM: if (!Check(S, DecodeYRegs_EvenIfRequiredRegClassByHwMode(MI, tmp, Address, Decoder))) { return MCDisassembler::Fail; }
-// DISASM: if (!Check(S, DecodeXRegs_EvenIfRequiredRegClassByHwMode(MI, tmp, Address, Decoder))) { return MCDisassembler::Fail; }
+// DISASM: tmp = fieldFromInstruction(insn, 0, 3);
+// DISASM: if (!Check(S, DecodeYRegs_EvenIfRequiredRegClassByHwMode(MI, tmp, Address, Decoder))) return dbgFailOpd("dst", "field(0,3)", "DecodeYRegs_EvenIfRequiredRegClassByHwMode");
+// DISASM: tmp = fieldFromInstruction(insn, 3, 2);
+// DISASM: if (!Check(S, DecodeXRegs_EvenIfRequiredRegClassByHwMode(MI, tmp, Address, Decoder))) return dbgFailOpd("src", "field(3,2)", "DecodeXRegs_EvenIfRequiredRegClassByHwMode");
 
 // DISASM: case 1:
-// DISASM: if (!Check(S, DecodeXRegs_EvenIfRequiredRegClassByHwMode(MI, tmp, Address, Decoder))) { return MCDisassembler::Fail; }
+// DISASM: tmp = fieldFromInstruction(insn, 3, 2);
+// DISASM: if (!Check(S, DecodeXRegs_EvenIfRequiredRegClassByHwMode(MI, tmp, Address, Decoder))) return dbgFailOpd("src", "field(3,2)", "DecodeXRegs_EvenIfRequiredRegClassByHwMode");
 
 // DISASM: case 2:
-// DISASM: if (!Check(S, DecodeXRegs_EvenRegisterClass(MI, tmp, Address, Decoder))) { return MCDisassembler::Fail; }
+// DISASM: tmp = fieldFromInstruction(insn, 3, 2);
+// DISASM: if (!Check(S, DecodeXRegs_EvenRegisterClass(MI, tmp, Address, Decoder))) return dbgFailOpd("src", "field(3,2)", "DecodeXRegs_EvenRegisterClass");
 // DISASM: case 3:
-// DISASM: if (!Check(S, DecodeXRegsRegisterClass(MI, tmp, Address, Decoder))) { return MCDisassembler::Fail; }
+// DISASM: tmp = fieldFromInstruction(insn, 3, 2);
+// DISASM: if (!Check(S, DecodeXRegsRegisterClass(MI, tmp, Address, Decoder))) return dbgFailOpd("src", "field(3,2)", "DecodeXRegsRegisterClass");
 
 // DISASM: case 4:
-// DISASM: if (!Check(S, YEvenIfRequiredCustomDecoder(MI, tmp, Address, Decoder))) { return MCDisassembler::Fail; }
+// DISASM: tmp = fieldFromInstruction(insn, 3, 2);
+// DISASM: if (!Check(S, YEvenIfRequiredCustomDecoder(MI, tmp, Address, Decoder))) return dbgFailOpd("src", "field(3,2)", "YEvenIfRequiredCustomDecoder");
 
 
 // ISEL-SDAG: MatcherTable
diff --git a/llvm/utils/TableGen/DecoderEmitter.cpp b/llvm/utils/TableGen/DecoderEmitter.cpp
index f8ebdfccda46f..b0a2b03ee9cf9 100644
--- a/llvm/utils/TableGen/DecoderEmitter.cpp
+++ b/llvm/utils/TableGen/DecoderEmitter.cpp
@@ -683,6 +683,61 @@ static std::vector<EncodingIsland> getIslands(const KnownBits &EncodingBits,
   return Islands;
 }
 
+static std::string getOperandFieldDescForDebug(const OperandInfo &OpInfo) {
+  if (OpInfo.Fields.empty() && !OpInfo.InitValue)
+    return "bits<0>";
+  if (OpInfo.Fields.empty())
+    return "imm";
+  std::string S;
+  raw_string_ostream OS(S);
+  ListSeparator LS(" + ");
+  for (const auto &EF : OpInfo.Fields)
+    OS << LS << formatv("field({},{})", EF.Base, EF.Width);
+  return S;
+}
+
+/// Emit `if (!Check(...)) return <Helper>(<Args>[, &DecodeComplete]);`. The
+/// connector strings (": ", " using ", " : FAIL") live once inside the helper
+/// rather than being baked into every per-site string literal, so each call
+/// site only carries the unique parts (op name, field desc, decoder name) as
+/// separate string arguments — letting the linker dedup them.
+static void emitCheckWithDbgMsg(raw_ostream &OS, indent Indent,
+                                const Twine &CheckCall, StringRef Helper,
+                                const Twine &Args,
+                                bool SetDecodeCompleteOnFail) {
+  OS << Indent << "if (!Check(S, " << CheckCall << ")) return " << Helper
+     << "(" << Args;
+  if (SetDecodeCompleteOnFail)
+    OS << ", &DecodeComplete";
+  OS << ");\n";
+}
+
+/// Operand-level decoder (emitBinaryParser).
+static void emitDecoderCheckWithOpcDebug(raw_ostream &OS, indent Indent,
+                                         const OperandInfo &OpInfo,
+                                         const Twine &CheckCall) {
+  StringRef OpName = OpInfo.Name.empty() ? "opd" : OpInfo.Name;
+  std::string FieldDesc = getOperandFieldDescForDebug(OpInfo);
+  StringRef DecoderName = OpInfo.Decoder;
+
+  emitCheckWithDbgMsg(
+      OS, Indent, CheckCall, "dbgFailOpd",
+      formatv("\"{}\", \"{}\", \"{}\"", OpName, FieldDesc, DecoderName),
+      !OpInfo.HasCompleteDecoder);
+}
+
+/// Whole-instruction \p DecoderMethod. Used when the encoding
+/// has a custom \p DecoderMethod (whole-instruction decoder).
+static void emitDecoderMethodOpcDebug(raw_ostream &OS, indent Indent,
+                                      const InstructionEncoding &Encoding,
+                                      StringRef DecoderMethod) {
+  StringRef EncName = Encoding.getName();
+  emitCheckWithDbgMsg(
+      OS, Indent, formatv("{}(MI, insn, Address, Decoder)", DecoderMethod),
+      "dbgFailInsn", formatv("\"{}\", \"{}\"", EncName, DecoderMethod),
+      !Encoding.hasCompleteDecoder());
+}
+
 static void emitBinaryParser(raw_ostream &OS, indent Indent,
                              const InstructionEncoding &Encoding,
                              const OperandInfo &OpInfo) {
@@ -702,8 +757,8 @@ static void emitBinaryParser(raw_ostream &OS, indent Indent,
     // The operand has no encoding, so the corresponding argument is omitted.
     // This avoids confusion and allows the function to be overloaded if the
     // operand does have an encoding in other instructions.
-    OS << Indent << "if (!Check(S, " << OpInfo.Decoder << "(MI, Decoder)))\n"
-       << Indent << "  return MCDisassembler::Fail;\n";
+    emitDecoderCheckWithOpcDebug(OS, Indent, OpInfo,
+                                 formatv("{}(MI, Decoder)", OpInfo.Decoder));
     return;
   }
 
@@ -738,10 +793,8 @@ static void emitBinaryParser(raw_ostream &OS, indent Indent,
 
   StringRef Decoder = OpInfo.Decoder;
   if (!Decoder.empty()) {
-    OS << Indent << "if (!Check(S, " << Decoder
-       << "(MI, tmp, Address, Decoder))) { "
-       << (OpInfo.HasCompleteDecoder ? "" : "DecodeComplete = false; ")
-       << "return MCDisassembler::Fail; }\n";
+    emitDecoderCheckWithOpcDebug(
+        OS, Indent, OpInfo, formatv("{}(MI, tmp, Address, Decoder)", Decoder));
   } else {
     OS << Indent << "MI.addOperand(MCOperand::createImm(tmp));\n";
   }
@@ -755,10 +808,7 @@ static std::string getDecoderString(const InstructionEncoding &Encoding) {
   // If a custom instruction decoder was specified, use that.
   StringRef DecoderMethod = Encoding.getDecoderMethod();
   if (!DecoderMethod.empty()) {
-    OS << Indent << "if (!Check(S, " << DecoderMethod
-       << "(MI, insn, Address, Decoder))) { "
-       << (Encoding.hasCompleteDecoder() ? "" : "DecodeComplete = false; ")
-       << "return MCDisassembler::Fail; }\n";
+    emitDecoderMethodOpcDebug(OS, Indent, Encoding, DecoderMethod);
   } else {
     for (const OperandInfo &Op : Encoding.getOperands())
       emitBinaryParser(OS, Indent, Encoding, Op);
@@ -1184,8 +1234,8 @@ static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], MCInst &MI,
       S = decodeToMCInst(DecodeIdx, S, insn, MI, Address, DisAsm,
                          DecodeComplete);
       LLVM_DEBUG(dbgs() << Loc << ": OPC_Decode: opcode " << Opc
-                        << ", using decoder " << DecodeIdx << ": "
-                        << (S ? "PASS, " : "FAIL, "));
+                        << " using decoder " << DecodeIdx
+                        << ": " << (S ? "PASS, " : "FAIL, "));
 
       if (DecodeComplete) {
         LLVM_DEBUG(dbgs() << "decoding complete\n");
@@ -1517,6 +1567,24 @@ namespace {
 // on their usage.
 template <typename T> constexpr uint32_t InsnBitWidth = 0;
 
+DecodeStatus dbgFailOpd(const char *Op, const char *Desc, const char *Decoder,
+                       bool *DecodeComplete = nullptr) {
+  LLVM_DEBUG(dbgs() << "OPC_Decode for " << Op << ": " << Desc << " using "
+                    << Decoder << " : FAIL\n");
+  if (DecodeComplete)
+    *DecodeComplete = false;
+  return MCDisassembler::Fail;
+}
+
+DecodeStatus dbgFailInsn(const char *Name, const char *Decoder,
+                         bool *DecodeComplete = nullptr) {
+  LLVM_DEBUG(dbgs() << "OPC_Decode for " << Name << ": insn using " << Decoder
+                    << " : FAIL\n");
+  if (DecodeComplete)
+    *DecodeComplete = false;
+  return MCDisassembler::Fail;
+}
+
 )";
 
   // Do extra bookkeeping for variable-length encodings.



More information about the llvm-commits mailing list