[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