[llvm] [LLVM][MC][DecoderEmitter] Add early failure if `Insn` and decoder table bitwidths mismatch (PR #156734)

Rahul Joshi via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 3 14:49:25 PDT 2025


https://github.com/jurahul updated https://github.com/llvm/llvm-project/pull/156734

>From d5874183149d1d383f60baacff9570795a13649c Mon Sep 17 00:00:00 2001
From: Rahul Joshi <rjoshi at nvidia.com>
Date: Wed, 3 Sep 2025 11:56:11 -0700
Subject: [PATCH 1/2] [LLVM][MC][DecoderEmitter] Encode BitWidth at the start
 of the table

---
 .../DecoderEmitterBitwidthSpecialization.td   | 22 ++++++++++---
 llvm/utils/TableGen/DecoderEmitter.cpp        | 32 +++++++++++++++++--
 2 files changed, 47 insertions(+), 7 deletions(-)

diff --git a/llvm/test/TableGen/DecoderEmitterBitwidthSpecialization.td b/llvm/test/TableGen/DecoderEmitterBitwidthSpecialization.td
index b4142e983ef77..701f5ce430bc0 100644
--- a/llvm/test/TableGen/DecoderEmitterBitwidthSpecialization.td
+++ b/llvm/test/TableGen/DecoderEmitterBitwidthSpecialization.td
@@ -105,7 +105,8 @@ def Inst3 : Instruction16Bit<3> {
 // When we specialize per bitwidth, we emit 2 decodeToMCInst functions and
 // DecodeIdx is assigned per bit width.
 
-// CHECK-SPECIALIZE-NO-TABLE-LABEL:   DecoderTable8[25]
+// CHECK-SPECIALIZE-NO-TABLE-LABEL:   DecoderTable8[26]
+// CHECK-SPECIALIZE-NO-TABLE:           /* 0 */ 8, // Bitwidth 8
 // CHECK-SPECIALIZE-NO-TABLE:           DecodeIdx: 0
 // CHECK-SPECIALIZE-NO-TABLE:           DecodeIdx: 1
 // CHECK-SPECIALIZE-NO-TABLE:         };
@@ -116,7 +117,8 @@ def Inst3 : Instruction16Bit<3> {
 // CHECK-SPECIALIZE-NO-TABLE:           case 0
 // CHECK-SPECIALIZE-NO-TABLE:           case 1
 
-// CHECK-SPECIALIZE-NO-TABLE-LABEL:   DecoderTable16[25]
+// CHECK-SPECIALIZE-NO-TABLE-LABEL:   DecoderTable16[26]
+// CHECK-SPECIALIZE-NO-TABLE:           /* 0 */ 16, // Bitwidth 16
 // CHECK-SPECIALIZE-NO-TABLE:           DecodeIdx: 0
 // CHECK-SPECIALIZE-NO-TABLE:           DecodeIdx: 1
 // CHECK-SPECIALIZE-NO-TABLE:         };
@@ -127,11 +129,17 @@ def Inst3 : Instruction16Bit<3> {
 // CHECK-SPECIALIZE-NO-TABLE:           case 0
 // CHECK-SPECIALIZE-NO-TABLE:           case 1
 
+// CHECK-SPECIALIZE-NO-TABLE-LABEL:   template <typename InsnType>
+// CHECK-SPECIALIZE-NO-TABLE-NEXT:    decodeInstruction
+// CHECK-SPECIALIZE-NO-TABLE:         uint32_t BitWidth = decodeULEB128AndIncUnsafe(Ptr);
+// CHECK-SPECIALIZE-NO-TABLE-NEXT:    if (InsnBitWidth<InsnType> != BitWidth)
+
 // -----------------------------------------------------------------------------
 // Per bitwidth specialization with function table.
 
 // 8 bit deccoder table, functions, and function table.
-// CHECK-SPECIALIZE-TABLE-LABEL:    DecoderTable8[25]
+// CHECK-SPECIALIZE-TABLE-LABEL:    DecoderTable8[26]
+// CHECK-SPECIALIZE-TABLE:           /* 0 */ 8, // Bitwidth 8
 // CHECK-SPECIALIZE-TABLE:            DecodeIdx: 0
 // CHECK-SPECIALIZE-TABLE:            DecodeIdx: 1
 // CHECK-SPECIALIZE-TABLE:          };
@@ -153,7 +161,8 @@ def Inst3 : Instruction16Bit<3> {
 // CHECK-SPECIALIZE-TABLE-NEXT:     };
 
 // 16 bit deccoder table, functions, and function table.
-// CHECK-SPECIALIZE-TABLE-LABEL:    DecoderTable16[25]
+// CHECK-SPECIALIZE-TABLE-LABEL:    DecoderTable16[26]
+// CHECK-SPECIALIZE-TABLE:            /* 0 */ 16, // Bitwidth 16
 // CHECK-SPECIALIZE-TABLE:            DecodeIdx: 0
 // CHECK-SPECIALIZE-TABLE:            DecodeIdx: 1
 // CHECK-SPECIALIZE-TABLE:          };
@@ -173,3 +182,8 @@ def Inst3 : Instruction16Bit<3> {
 // CHECK-SPECIALIZE-TABLE-NEXT:       decodeFn_16bit_0,
 // CHECK-SPECIALIZE-TABLE-NEXT:       decodeFn_16bit_1,
 // CHECK-SPECIALIZE-TABLE-NEXT:     };
+
+// CHECK-SPECIALIZE-TABLE-LABEL:    template <typename InsnType>
+// CHECK-SPECIALIZE-TABLE-NEXT:     decodeInstruction
+// CHECK-SPECIALIZE-TABLE:          uint32_t BitWidth = decodeULEB128AndIncUnsafe(Ptr);
+// CHECK-SPECIALIZE-TABLE-NEXT:     if (InsnBitWidth<InsnType> != BitWidth)
diff --git a/llvm/utils/TableGen/DecoderEmitter.cpp b/llvm/utils/TableGen/DecoderEmitter.cpp
index fcaf433918092..8479e228d38cd 100644
--- a/llvm/utils/TableGen/DecoderEmitter.cpp
+++ b/llvm/utils/TableGen/DecoderEmitter.cpp
@@ -611,7 +611,11 @@ class DecoderTableBuilder {
                       DecoderTableInfo &TableInfo)
       : Target(Target), Encodings(Encodings), TableInfo(TableInfo) {}
 
-  void buildTable(const FilterChooser &FC) const {
+  void buildTable(const FilterChooser &FC, unsigned BitWidth) const {
+    // When specializing decoders per bit width, each decoder table will begin
+    // with the bitwidth for that table.
+    if (SpecializeDecodersPerBitwidth)
+      TableInfo.Table.insertULEB128(BitWidth);
     emitTableEntries(FC);
     assert(TableInfo.FixupStack.empty() && "Fixup stack phasing error!");
   }
@@ -774,6 +778,15 @@ unsigned DecoderEmitter::emitTable(formatted_raw_ostream &OS,
     OS << "Skip to: " << Index;
   };
 
+  // The first entry when specializing decoders per bitwidth is the bitwidth.
+  // This will be used for early return in `decodeInstruction`.
+  if (SpecializeDecodersPerBitwidth) {
+    OS << "/* 0  */";
+    OS.PadToColumn(14);
+    emitULEB128(I, OS);
+    OS << " // Bitwidth " << BitWidth << '\n';
+  }
+
   unsigned OpcodeMask = 0;
 
   while (I != E) {
@@ -2108,9 +2121,22 @@ static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], MCInst &MI,
   if (HasCheckPredicate)
     OS << "  const FeatureBitset &Bits = STI.getFeatureBits();\n";
   OS << "  using namespace llvm::MCD;\n";
+  OS << "  const uint8_t *Ptr = DecodeTable;\n";
+
+  if (SpecializeDecodersPerBitwidth) {
+    // Return early if the decoder table's bitwidth does not match `InsnType`
+    // bitwidth.
+    OS << R"(
+  uint32_t BitWidth = decodeULEB128AndIncUnsafe(Ptr);
+  if (InsnBitWidth<InsnType> != BitWidth) {
+    LLVM_DEBUG({
+      dbgs() << "Mismatch between table bitwidth and instruction bitwidth";
+    });
+    return MCDisassembler::Fail;
+  })";
+  }
 
   OS << R"(
-  const uint8_t *Ptr = DecodeTable;
   uint64_t CurFieldValue = 0;
   DecodeStatus S = MCDisassembler::Success;
   while (true) {
@@ -2554,7 +2580,7 @@ template <typename T> constexpr uint32_t InsnBitWidth = 0;
       //    across all decoder tables.
       //  - predicates are shared across all decoder tables.
       TableInfo.Table.clear();
-      TableBuilder.buildTable(FC);
+      TableBuilder.buildTable(FC, BitWidth);
 
       // Print the table to the output stream.
       OpcodeMask |= emitTable(OS, TableInfo.Table, DecoderNamespace, HwModeID,

>From 9d3eec2ca99dc6529372e5f717630000b8b9884e Mon Sep 17 00:00:00 2001
From: Rahul Joshi <rjoshi at nvidia.com>
Date: Wed, 3 Sep 2025 14:46:37 -0700
Subject: [PATCH 2/2] Make mismatch a fatal error

---
 llvm/utils/TableGen/DecoderEmitter.cpp | 15 ++++++---------
 1 file changed, 6 insertions(+), 9 deletions(-)

diff --git a/llvm/utils/TableGen/DecoderEmitter.cpp b/llvm/utils/TableGen/DecoderEmitter.cpp
index 8479e228d38cd..6e866d816d2cb 100644
--- a/llvm/utils/TableGen/DecoderEmitter.cpp
+++ b/llvm/utils/TableGen/DecoderEmitter.cpp
@@ -779,7 +779,7 @@ unsigned DecoderEmitter::emitTable(formatted_raw_ostream &OS,
   };
 
   // The first entry when specializing decoders per bitwidth is the bitwidth.
-  // This will be used for early return in `decodeInstruction`.
+  // This will be used for additional checks in `decodeInstruction`.
   if (SpecializeDecodersPerBitwidth) {
     OS << "/* 0  */";
     OS.PadToColumn(14);
@@ -2124,16 +2124,13 @@ static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], MCInst &MI,
   OS << "  const uint8_t *Ptr = DecodeTable;\n";
 
   if (SpecializeDecodersPerBitwidth) {
-    // Return early if the decoder table's bitwidth does not match `InsnType`
-    // bitwidth.
+    // Fail with a fatal error if decoder table's bitwidth does not match
+    // `InsnType` bitwidth.
     OS << R"(
   uint32_t BitWidth = decodeULEB128AndIncUnsafe(Ptr);
-  if (InsnBitWidth<InsnType> != BitWidth) {
-    LLVM_DEBUG({
-      dbgs() << "Mismatch between table bitwidth and instruction bitwidth";
-    });
-    return MCDisassembler::Fail;
-  })";
+  if (InsnBitWidth<InsnType> != BitWidth)
+    llvm_unreachable("Table and instruction bitwidth mismatch");
+)";
   }
 
   OS << R"(



More information about the llvm-commits mailing list