[llvm] [TableGen][DecoderEmitter] Add option to emit type-specialized `decodeToMCInst` (PR #146593)

Rahul Joshi via llvm-commits llvm-commits at lists.llvm.org
Fri Jul 11 18:03:55 PDT 2025


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

>From 5d929c1c1acd5ffdf37587baa9da4dcd2990b0be Mon Sep 17 00:00:00 2001
From: Rahul Joshi <rjoshi at nvidia.com>
Date: Tue, 1 Jul 2025 09:47:10 -0700
Subject: [PATCH 1/7] [TableGen][DecoderEmitter] Add option to emit
 type-specialized `decodeToMCInst`

---
 llvm/lib/Target/AArch64/CMakeLists.txt   |   3 +-
 llvm/lib/Target/AMDGPU/CMakeLists.txt    |   5 +-
 llvm/lib/Target/ARC/CMakeLists.txt       |   4 +-
 llvm/lib/Target/ARM/CMakeLists.txt       |   4 +-
 llvm/lib/Target/AVR/CMakeLists.txt       |   3 +-
 llvm/lib/Target/BPF/CMakeLists.txt       |   3 +-
 llvm/lib/Target/CSKY/CMakeLists.txt      |   3 +-
 llvm/lib/Target/Hexagon/CMakeLists.txt   |   3 +-
 llvm/lib/Target/Lanai/CMakeLists.txt     |   3 +-
 llvm/lib/Target/LoongArch/CMakeLists.txt |   3 +-
 llvm/lib/Target/MSP430/CMakeLists.txt    |   3 +-
 llvm/lib/Target/Mips/CMakeLists.txt      |   3 +-
 llvm/lib/Target/PowerPC/CMakeLists.txt   |   3 +-
 llvm/lib/Target/RISCV/CMakeLists.txt     |   4 +-
 llvm/lib/Target/Sparc/CMakeLists.txt     |   3 +-
 llvm/lib/Target/SystemZ/CMakeLists.txt   |   3 +-
 llvm/lib/Target/VE/CMakeLists.txt        |   3 +-
 llvm/lib/Target/XCore/CMakeLists.txt     |   4 +-
 llvm/lib/Target/Xtensa/CMakeLists.txt    |   3 +-
 llvm/test/TableGen/VarLenDecoder.td      |  13 +-
 llvm/utils/TableGen/DecoderEmitter.cpp   | 187 ++++++++++++++++++-----
 21 files changed, 202 insertions(+), 61 deletions(-)

diff --git a/llvm/lib/Target/AArch64/CMakeLists.txt b/llvm/lib/Target/AArch64/CMakeLists.txt
index 66136a464f05d..98cc8693144f0 100644
--- a/llvm/lib/Target/AArch64/CMakeLists.txt
+++ b/llvm/lib/Target/AArch64/CMakeLists.txt
@@ -7,7 +7,8 @@ tablegen(LLVM AArch64GenAsmWriter.inc -gen-asm-writer)
 tablegen(LLVM AArch64GenAsmWriter1.inc -gen-asm-writer -asmwriternum=1)
 tablegen(LLVM AArch64GenCallingConv.inc -gen-callingconv)
 tablegen(LLVM AArch64GenDAGISel.inc -gen-dag-isel)
-tablegen(LLVM AArch64GenDisassemblerTables.inc -gen-disassembler)
+tablegen(LLVM AArch64GenDisassemblerTables.inc -gen-disassembler
+              -non-templated-decode-to-mcinst-type-spec=uint32_t:=32)
 tablegen(LLVM AArch64GenFastISel.inc -gen-fast-isel)
 tablegen(LLVM AArch64GenGlobalISel.inc -gen-global-isel)
 tablegen(LLVM AArch64GenO0PreLegalizeGICombiner.inc -gen-global-isel-combiner
diff --git a/llvm/lib/Target/AMDGPU/CMakeLists.txt b/llvm/lib/Target/AMDGPU/CMakeLists.txt
index e3519f192137c..6254750c10c3c 100644
--- a/llvm/lib/Target/AMDGPU/CMakeLists.txt
+++ b/llvm/lib/Target/AMDGPU/CMakeLists.txt
@@ -6,7 +6,10 @@ tablegen(LLVM AMDGPUGenAsmMatcher.inc -gen-asm-matcher)
 tablegen(LLVM AMDGPUGenAsmWriter.inc -gen-asm-writer)
 tablegen(LLVM AMDGPUGenCallingConv.inc -gen-callingconv)
 tablegen(LLVM AMDGPUGenDAGISel.inc -gen-dag-isel)
-tablegen(LLVM AMDGPUGenDisassemblerTables.inc -gen-disassembler)
+tablegen(LLVM AMDGPUGenDisassemblerTables.inc -gen-disassembler
+         -non-templated-decode-to-mcinst-type-spec=uint32_t:=32
+         -non-templated-decode-to-mcinst-type-spec=uint64_t:=64
+         -non-templated-decode-to-mcinst-type-spec=DecoderUInt128:=96,128)
 tablegen(LLVM AMDGPUGenInstrInfo.inc -gen-instr-info)
 tablegen(LLVM AMDGPUGenMCCodeEmitter.inc -gen-emitter)
 tablegen(LLVM AMDGPUGenMCPseudoLowering.inc -gen-pseudo-lowering)
diff --git a/llvm/lib/Target/ARC/CMakeLists.txt b/llvm/lib/Target/ARC/CMakeLists.txt
index 196cc31cc5080..e6656576fbcc3 100644
--- a/llvm/lib/Target/ARC/CMakeLists.txt
+++ b/llvm/lib/Target/ARC/CMakeLists.txt
@@ -5,7 +5,9 @@ set(LLVM_TARGET_DEFINITIONS ARC.td)
 tablegen(LLVM ARCGenAsmWriter.inc -gen-asm-writer)
 tablegen(LLVM ARCGenCallingConv.inc -gen-callingconv)
 tablegen(LLVM ARCGenDAGISel.inc -gen-dag-isel)
-tablegen(LLVM ARCGenDisassemblerTables.inc -gen-disassembler)
+tablegen(LLVM ARCGenDisassemblerTables.inc -gen-disassembler
+         -non-templated-decode-to-mcinst-type-spec=uint32_t:=16,32
+         -non-templated-decode-to-mcinst-type-spec=uint64_t:=48,64)
 tablegen(LLVM ARCGenInstrInfo.inc -gen-instr-info)
 tablegen(LLVM ARCGenRegisterInfo.inc -gen-register-info)
 tablegen(LLVM ARCGenSDNodeInfo.inc -gen-sd-node-info)
diff --git a/llvm/lib/Target/ARM/CMakeLists.txt b/llvm/lib/Target/ARM/CMakeLists.txt
index a39629bd8aeb0..718a084ec6388 100644
--- a/llvm/lib/Target/ARM/CMakeLists.txt
+++ b/llvm/lib/Target/ARM/CMakeLists.txt
@@ -6,7 +6,9 @@ tablegen(LLVM ARMGenAsmMatcher.inc -gen-asm-matcher)
 tablegen(LLVM ARMGenAsmWriter.inc -gen-asm-writer)
 tablegen(LLVM ARMGenCallingConv.inc -gen-callingconv)
 tablegen(LLVM ARMGenDAGISel.inc -gen-dag-isel)
-tablegen(LLVM ARMGenDisassemblerTables.inc -gen-disassembler)
+tablegen(LLVM ARMGenDisassemblerTables.inc -gen-disassembler
+         -non-templated-decode-to-mcinst-type-spec=uint16_t:=16
+         -non-templated-decode-to-mcinst-type-spec=uint32_t:=32)
 tablegen(LLVM ARMGenFastISel.inc -gen-fast-isel)
 tablegen(LLVM ARMGenGlobalISel.inc -gen-global-isel)
 tablegen(LLVM ARMGenInstrInfo.inc -gen-instr-info)
diff --git a/llvm/lib/Target/AVR/CMakeLists.txt b/llvm/lib/Target/AVR/CMakeLists.txt
index 781dac02c7083..a2da85d77a325 100644
--- a/llvm/lib/Target/AVR/CMakeLists.txt
+++ b/llvm/lib/Target/AVR/CMakeLists.txt
@@ -6,7 +6,8 @@ tablegen(LLVM AVRGenAsmMatcher.inc -gen-asm-matcher)
 tablegen(LLVM AVRGenAsmWriter.inc -gen-asm-writer)
 tablegen(LLVM AVRGenCallingConv.inc -gen-callingconv)
 tablegen(LLVM AVRGenDAGISel.inc -gen-dag-isel)
-tablegen(LLVM AVRGenDisassemblerTables.inc -gen-disassembler)
+tablegen(LLVM AVRGenDisassemblerTables.inc -gen-disassembler
+         -non-templated-decode-to-mcinst-type-spec=uint32_t:=16,32)
 tablegen(LLVM AVRGenInstrInfo.inc -gen-instr-info)
 tablegen(LLVM AVRGenMCCodeEmitter.inc -gen-emitter)
 tablegen(LLVM AVRGenRegisterInfo.inc -gen-register-info)
diff --git a/llvm/lib/Target/BPF/CMakeLists.txt b/llvm/lib/Target/BPF/CMakeLists.txt
index eade4cacb7100..6a609d645dfa1 100644
--- a/llvm/lib/Target/BPF/CMakeLists.txt
+++ b/llvm/lib/Target/BPF/CMakeLists.txt
@@ -6,7 +6,8 @@ tablegen(LLVM BPFGenAsmMatcher.inc -gen-asm-matcher)
 tablegen(LLVM BPFGenAsmWriter.inc -gen-asm-writer)
 tablegen(LLVM BPFGenCallingConv.inc -gen-callingconv)
 tablegen(LLVM BPFGenDAGISel.inc -gen-dag-isel)
-tablegen(LLVM BPFGenDisassemblerTables.inc -gen-disassembler)
+tablegen(LLVM BPFGenDisassemblerTables.inc -gen-disassembler
+              -non-templated-decode-to-mcinst-type-spec=uint64_t:=64)
 tablegen(LLVM BPFGenInstrInfo.inc -gen-instr-info)
 tablegen(LLVM BPFGenMCCodeEmitter.inc -gen-emitter)
 tablegen(LLVM BPFGenRegisterInfo.inc -gen-register-info)
diff --git a/llvm/lib/Target/CSKY/CMakeLists.txt b/llvm/lib/Target/CSKY/CMakeLists.txt
index 4b900bc99c271..eadf0169edef1 100644
--- a/llvm/lib/Target/CSKY/CMakeLists.txt
+++ b/llvm/lib/Target/CSKY/CMakeLists.txt
@@ -7,7 +7,8 @@ tablegen(LLVM CSKYGenAsmWriter.inc -gen-asm-writer)
 tablegen(LLVM CSKYGenCallingConv.inc -gen-callingconv)
 tablegen(LLVM CSKYGenCompressInstEmitter.inc -gen-compress-inst-emitter)
 tablegen(LLVM CSKYGenDAGISel.inc -gen-dag-isel)
-tablegen(LLVM CSKYGenDisassemblerTables.inc -gen-disassembler)
+tablegen(LLVM CSKYGenDisassemblerTables.inc -gen-disassembler
+              -non-templated-decode-to-mcinst-type-spec=uint32_t:=16,32)
 tablegen(LLVM CSKYGenInstrInfo.inc -gen-instr-info)
 tablegen(LLVM CSKYGenMCCodeEmitter.inc -gen-emitter)
 tablegen(LLVM CSKYGenMCPseudoLowering.inc -gen-pseudo-lowering)
diff --git a/llvm/lib/Target/Hexagon/CMakeLists.txt b/llvm/lib/Target/Hexagon/CMakeLists.txt
index d758260a8ab5d..be2bc89155612 100644
--- a/llvm/lib/Target/Hexagon/CMakeLists.txt
+++ b/llvm/lib/Target/Hexagon/CMakeLists.txt
@@ -7,7 +7,8 @@ tablegen(LLVM HexagonGenAsmWriter.inc -gen-asm-writer)
 tablegen(LLVM HexagonGenCallingConv.inc -gen-callingconv)
 tablegen(LLVM HexagonGenDAGISel.inc -gen-dag-isel)
 tablegen(LLVM HexagonGenDFAPacketizer.inc -gen-dfa-packetizer)
-tablegen(LLVM HexagonGenDisassemblerTables.inc -gen-disassembler)
+tablegen(LLVM HexagonGenDisassemblerTables.inc -gen-disassembler
+              -non-templated-decode-to-mcinst-type-spec=uint32_t:=32)
 tablegen(LLVM HexagonGenInstrInfo.inc -gen-instr-info)
 tablegen(LLVM HexagonGenMCCodeEmitter.inc -gen-emitter)
 tablegen(LLVM HexagonGenRegisterInfo.inc -gen-register-info)
diff --git a/llvm/lib/Target/Lanai/CMakeLists.txt b/llvm/lib/Target/Lanai/CMakeLists.txt
index 4a628e13fc177..dfb0c93e1a5e3 100644
--- a/llvm/lib/Target/Lanai/CMakeLists.txt
+++ b/llvm/lib/Target/Lanai/CMakeLists.txt
@@ -6,7 +6,8 @@ tablegen(LLVM LanaiGenAsmMatcher.inc -gen-asm-matcher)
 tablegen(LLVM LanaiGenAsmWriter.inc -gen-asm-writer)
 tablegen(LLVM LanaiGenCallingConv.inc -gen-callingconv)
 tablegen(LLVM LanaiGenDAGISel.inc -gen-dag-isel)
-tablegen(LLVM LanaiGenDisassemblerTables.inc -gen-disassembler)
+tablegen(LLVM LanaiGenDisassemblerTables.inc -gen-disassembler
+              -non-templated-decode-to-mcinst-type-spec=uint32_t:=32)
 tablegen(LLVM LanaiGenInstrInfo.inc -gen-instr-info)
 tablegen(LLVM LanaiGenMCCodeEmitter.inc -gen-emitter)
 tablegen(LLVM LanaiGenRegisterInfo.inc -gen-register-info)
diff --git a/llvm/lib/Target/LoongArch/CMakeLists.txt b/llvm/lib/Target/LoongArch/CMakeLists.txt
index 0f674b1b0fa9e..c851f5c2fc1da 100644
--- a/llvm/lib/Target/LoongArch/CMakeLists.txt
+++ b/llvm/lib/Target/LoongArch/CMakeLists.txt
@@ -5,7 +5,8 @@ set(LLVM_TARGET_DEFINITIONS LoongArch.td)
 tablegen(LLVM LoongArchGenAsmMatcher.inc -gen-asm-matcher)
 tablegen(LLVM LoongArchGenAsmWriter.inc -gen-asm-writer)
 tablegen(LLVM LoongArchGenDAGISel.inc -gen-dag-isel)
-tablegen(LLVM LoongArchGenDisassemblerTables.inc -gen-disassembler)
+tablegen(LLVM LoongArchGenDisassemblerTables.inc -gen-disassembler
+              -non-templated-decode-to-mcinst-type-spec=uint32_t:=32)
 tablegen(LLVM LoongArchGenInstrInfo.inc -gen-instr-info)
 tablegen(LLVM LoongArchGenMCPseudoLowering.inc -gen-pseudo-lowering)
 tablegen(LLVM LoongArchGenMCCodeEmitter.inc -gen-emitter)
diff --git a/llvm/lib/Target/MSP430/CMakeLists.txt b/llvm/lib/Target/MSP430/CMakeLists.txt
index 4081d3472fd78..f10c8192e7df0 100644
--- a/llvm/lib/Target/MSP430/CMakeLists.txt
+++ b/llvm/lib/Target/MSP430/CMakeLists.txt
@@ -6,7 +6,8 @@ tablegen(LLVM MSP430GenAsmMatcher.inc -gen-asm-matcher)
 tablegen(LLVM MSP430GenAsmWriter.inc -gen-asm-writer)
 tablegen(LLVM MSP430GenCallingConv.inc -gen-callingconv)
 tablegen(LLVM MSP430GenDAGISel.inc -gen-dag-isel)
-tablegen(LLVM MSP430GenDisassemblerTables.inc -gen-disassembler)
+tablegen(LLVM MSP430GenDisassemblerTables.inc -gen-disassembler
+              -non-templated-decode-to-mcinst-type-spec=uint64_t:=16,32,48)
 tablegen(LLVM MSP430GenInstrInfo.inc -gen-instr-info)
 tablegen(LLVM MSP430GenMCCodeEmitter.inc -gen-emitter)
 tablegen(LLVM MSP430GenRegisterInfo.inc -gen-register-info)
diff --git a/llvm/lib/Target/Mips/CMakeLists.txt b/llvm/lib/Target/Mips/CMakeLists.txt
index 21d1765107ae6..2516d00706a91 100644
--- a/llvm/lib/Target/Mips/CMakeLists.txt
+++ b/llvm/lib/Target/Mips/CMakeLists.txt
@@ -6,7 +6,8 @@ tablegen(LLVM MipsGenAsmMatcher.inc -gen-asm-matcher)
 tablegen(LLVM MipsGenAsmWriter.inc -gen-asm-writer)
 tablegen(LLVM MipsGenCallingConv.inc -gen-callingconv)
 tablegen(LLVM MipsGenDAGISel.inc -gen-dag-isel)
-tablegen(LLVM MipsGenDisassemblerTables.inc -gen-disassembler)
+tablegen(LLVM MipsGenDisassemblerTables.inc -gen-disassembler
+              -non-templated-decode-to-mcinst-type-spec=uint32_t:=16,32)
 tablegen(LLVM MipsGenFastISel.inc -gen-fast-isel)
 tablegen(LLVM MipsGenGlobalISel.inc -gen-global-isel)
 tablegen(LLVM MipsGenPostLegalizeGICombiner.inc -gen-global-isel-combiner
diff --git a/llvm/lib/Target/PowerPC/CMakeLists.txt b/llvm/lib/Target/PowerPC/CMakeLists.txt
index 3808a26a0b92a..136db0634eb93 100644
--- a/llvm/lib/Target/PowerPC/CMakeLists.txt
+++ b/llvm/lib/Target/PowerPC/CMakeLists.txt
@@ -6,7 +6,8 @@ tablegen(LLVM PPCGenAsmMatcher.inc -gen-asm-matcher)
 tablegen(LLVM PPCGenAsmWriter.inc -gen-asm-writer)
 tablegen(LLVM PPCGenCallingConv.inc -gen-callingconv)
 tablegen(LLVM PPCGenDAGISel.inc -gen-dag-isel)
-tablegen(LLVM PPCGenDisassemblerTables.inc -gen-disassembler)
+tablegen(LLVM PPCGenDisassemblerTables.inc -gen-disassembler
+               -non-templated-decode-to-mcinst-type-spec=uint64_t:=32,64)
 tablegen(LLVM PPCGenFastISel.inc -gen-fast-isel)
 tablegen(LLVM PPCGenInstrInfo.inc -gen-instr-info)
 tablegen(LLVM PPCGenMCCodeEmitter.inc -gen-emitter)
diff --git a/llvm/lib/Target/RISCV/CMakeLists.txt b/llvm/lib/Target/RISCV/CMakeLists.txt
index e32d6eab3b977..9df6701387d43 100644
--- a/llvm/lib/Target/RISCV/CMakeLists.txt
+++ b/llvm/lib/Target/RISCV/CMakeLists.txt
@@ -7,7 +7,9 @@ tablegen(LLVM RISCVGenAsmWriter.inc -gen-asm-writer)
 tablegen(LLVM RISCVGenCompressInstEmitter.inc -gen-compress-inst-emitter)
 tablegen(LLVM RISCVGenMacroFusion.inc -gen-macro-fusion-pred)
 tablegen(LLVM RISCVGenDAGISel.inc -gen-dag-isel)
-tablegen(LLVM RISCVGenDisassemblerTables.inc -gen-disassembler)
+tablegen(LLVM RISCVGenDisassemblerTables.inc -gen-disassembler
+              -non-templated-decode-to-mcinst-type-spec=uint32_t:=16,32
+              -non-templated-decode-to-mcinst-type-spec=uint64_t:=48)
 tablegen(LLVM RISCVGenInstrInfo.inc -gen-instr-info)
 tablegen(LLVM RISCVGenMCCodeEmitter.inc -gen-emitter)
 tablegen(LLVM RISCVGenMCPseudoLowering.inc -gen-pseudo-lowering)
diff --git a/llvm/lib/Target/Sparc/CMakeLists.txt b/llvm/lib/Target/Sparc/CMakeLists.txt
index f682719ac483f..6334dbbc6cc1a 100644
--- a/llvm/lib/Target/Sparc/CMakeLists.txt
+++ b/llvm/lib/Target/Sparc/CMakeLists.txt
@@ -6,7 +6,8 @@ tablegen(LLVM SparcGenAsmMatcher.inc -gen-asm-matcher)
 tablegen(LLVM SparcGenAsmWriter.inc -gen-asm-writer)
 tablegen(LLVM SparcGenCallingConv.inc -gen-callingconv)
 tablegen(LLVM SparcGenDAGISel.inc -gen-dag-isel)
-tablegen(LLVM SparcGenDisassemblerTables.inc -gen-disassembler)
+tablegen(LLVM SparcGenDisassemblerTables.inc -gen-disassembler
+               -non-templated-decode-to-mcinst-type-spec=uint32_t:=32)
 tablegen(LLVM SparcGenInstrInfo.inc -gen-instr-info)
 tablegen(LLVM SparcGenMCCodeEmitter.inc -gen-emitter)
 tablegen(LLVM SparcGenRegisterInfo.inc -gen-register-info)
diff --git a/llvm/lib/Target/SystemZ/CMakeLists.txt b/llvm/lib/Target/SystemZ/CMakeLists.txt
index 0d8f3eac6ee4f..1caeef468f3fb 100644
--- a/llvm/lib/Target/SystemZ/CMakeLists.txt
+++ b/llvm/lib/Target/SystemZ/CMakeLists.txt
@@ -7,7 +7,8 @@ tablegen(LLVM SystemZGenGNUAsmWriter.inc -gen-asm-writer)
 tablegen(LLVM SystemZGenHLASMAsmWriter.inc -gen-asm-writer -asmwriternum=1)
 tablegen(LLVM SystemZGenCallingConv.inc -gen-callingconv)
 tablegen(LLVM SystemZGenDAGISel.inc -gen-dag-isel)
-tablegen(LLVM SystemZGenDisassemblerTables.inc -gen-disassembler)
+tablegen(LLVM SystemZGenDisassemblerTables.inc -gen-disassembler
+               -non-templated-decode-to-mcinst-type-spec=uint64_t:=16,32,48)
 tablegen(LLVM SystemZGenInstrInfo.inc -gen-instr-info)
 tablegen(LLVM SystemZGenMCCodeEmitter.inc -gen-emitter)
 tablegen(LLVM SystemZGenRegisterInfo.inc -gen-register-info)
diff --git a/llvm/lib/Target/VE/CMakeLists.txt b/llvm/lib/Target/VE/CMakeLists.txt
index d1bb4f32fcba7..6b83a3e7ae28e 100644
--- a/llvm/lib/Target/VE/CMakeLists.txt
+++ b/llvm/lib/Target/VE/CMakeLists.txt
@@ -4,7 +4,8 @@ set(LLVM_TARGET_DEFINITIONS VE.td)
 
 tablegen(LLVM VEGenRegisterInfo.inc -gen-register-info)
 tablegen(LLVM VEGenInstrInfo.inc -gen-instr-info)
-tablegen(LLVM VEGenDisassemblerTables.inc -gen-disassembler)
+tablegen(LLVM VEGenDisassemblerTables.inc -gen-disassembler
+               -non-templated-decode-to-mcinst-type-spec=uint64_t:=64)
 tablegen(LLVM VEGenMCCodeEmitter.inc -gen-emitter)
 tablegen(LLVM VEGenAsmWriter.inc -gen-asm-writer)
 tablegen(LLVM VEGenAsmMatcher.inc -gen-asm-matcher)
diff --git a/llvm/lib/Target/XCore/CMakeLists.txt b/llvm/lib/Target/XCore/CMakeLists.txt
index f411c658b43b0..3b5bf848d8144 100644
--- a/llvm/lib/Target/XCore/CMakeLists.txt
+++ b/llvm/lib/Target/XCore/CMakeLists.txt
@@ -5,7 +5,9 @@ set(LLVM_TARGET_DEFINITIONS XCore.td)
 tablegen(LLVM XCoreGenAsmWriter.inc -gen-asm-writer)
 tablegen(LLVM XCoreGenCallingConv.inc -gen-callingconv)
 tablegen(LLVM XCoreGenDAGISel.inc -gen-dag-isel)
-tablegen(LLVM XCoreGenDisassemblerTables.inc -gen-disassembler)
+tablegen(LLVM XCoreGenDisassemblerTables.inc -gen-disassembler
+          -non-templated-decode-to-mcinst-type-spec=uint16_t:=16
+          -non-templated-decode-to-mcinst-type-spec=uint32_t:=32)
 tablegen(LLVM XCoreGenInstrInfo.inc -gen-instr-info)
 tablegen(LLVM XCoreGenRegisterInfo.inc -gen-register-info)
 tablegen(LLVM XCoreGenSDNodeInfo.inc -gen-sd-node-info)
diff --git a/llvm/lib/Target/Xtensa/CMakeLists.txt b/llvm/lib/Target/Xtensa/CMakeLists.txt
index 4fc1ba6dfa650..9c825b5d880c7 100644
--- a/llvm/lib/Target/Xtensa/CMakeLists.txt
+++ b/llvm/lib/Target/Xtensa/CMakeLists.txt
@@ -6,7 +6,8 @@ tablegen(LLVM XtensaGenAsmMatcher.inc -gen-asm-matcher)
 tablegen(LLVM XtensaGenAsmWriter.inc -gen-asm-writer)
 tablegen(LLVM XtensaGenCallingConv.inc -gen-callingconv)
 tablegen(LLVM XtensaGenDAGISel.inc -gen-dag-isel)
-tablegen(LLVM XtensaGenDisassemblerTables.inc -gen-disassembler)
+tablegen(LLVM XtensaGenDisassemblerTables.inc -gen-disassembler
+               -non-templated-decode-to-mcinst-type-spec=uint64_t:=16,24)
 tablegen(LLVM XtensaGenInstrInfo.inc -gen-instr-info)
 tablegen(LLVM XtensaGenMCCodeEmitter.inc -gen-emitter)
 tablegen(LLVM XtensaGenRegisterInfo.inc -gen-register-info)
diff --git a/llvm/test/TableGen/VarLenDecoder.td b/llvm/test/TableGen/VarLenDecoder.td
index 06ff62294a196..2359bd2c15145 100644
--- a/llvm/test/TableGen/VarLenDecoder.td
+++ b/llvm/test/TableGen/VarLenDecoder.td
@@ -61,11 +61,7 @@ def FOO32 : MyVarInst<MemOp32> {
 // CHECK-LARGE-NEXT: /* 14 */      MCD::OPC_Decode, {{[0-9]+}}, {{[0-9]+}}, 1, // Opcode: FOO32
 // CHECK-LARGE-NEXT: /* 18 */      MCD::OPC_Fail,
 
-// Instruction length table
-// CHECK: 27,
-// CHECK-NEXT: 43,
-// CHECK-NEXT: };
-
+// CHECK-LABEL: decodeToMCInst
 // CHECK:      case 0:
 // CHECK-NEXT: tmp = fieldFromInstruction(insn, 8, 3);
 // CHECK-NEXT: if (!Check(S, DecodeRegClassRegisterClass(MI, tmp, Address, Decoder))) { return MCDisassembler::Fail; }
@@ -85,6 +81,13 @@ def FOO32 : MyVarInst<MemOp32> {
 // CHECK-NEXT: MI.addOperand(MCOperand::createImm(tmp));
 // CHECK-NEXT: return S;
 
+// Instruction length table
+// CHECK-LABEL: InstrLenTable
+// CHECK: 27,
+// CHECK-NEXT: 43,
+// CHECK-NEXT: };
+
+// CHECK-LABEL: decodeInstruction
 // CHECK-LABEL: case MCD::OPC_ExtractField: {
 // CHECK: makeUp(insn, Start + Len);
 
diff --git a/llvm/utils/TableGen/DecoderEmitter.cpp b/llvm/utils/TableGen/DecoderEmitter.cpp
index f523fc26a6671..fb51bd90fa961 100644
--- a/llvm/utils/TableGen/DecoderEmitter.cpp
+++ b/llvm/utils/TableGen/DecoderEmitter.cpp
@@ -23,6 +23,7 @@
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SetVector.h"
 #include "llvm/ADT/SmallBitVector.h"
+#include "llvm/ADT/SmallSet.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/Statistic.h"
 #include "llvm/ADT/StringExtras.h"
@@ -92,6 +93,22 @@ static cl::opt<bool> UseFnTableInDecodeToMCInst(
         "of the generated code."),
     cl::init(false), cl::cat(DisassemblerEmitterCat));
 
+// Option to generate a non-templated version of `decodeToMCInst`. The
+// templated `decodeToMCInst` is templated on `InsnType` and a given `InsnType`
+// can target instructions with one or more Bitwidths. So the option to
+// generate a non-templated `decodeToMCInst` is a typespec of the form
+// type::=list-of-sizes.
+
+// For example, for the AMDGPU target, the type `DecoderUInt128` is used for
+// both 96 and 128 bit instructions. So the generated non-templated
+// `decodeToMCInst` will support decoding both these instruction Bitwidths and
+// the option will be DecoderUInt128::=96,128
+static cl::list<std::string> DecodeToMCInstTypeSpecs(
+    "non-templated-decode-to-mcinst-type-spec",
+    cl::desc("list of C++ types and associated bitwidths to used to generate "
+             "non-templated `decodeToMCInst`."),
+    cl::cat(DisassemblerEmitterCat));
+
 STATISTIC(NumEncodings, "Number of encodings considered");
 STATISTIC(NumEncodingsLackingDisasm,
           "Number of encodings without disassembler info");
@@ -234,7 +251,7 @@ class DecoderEmitter {
   void emitPredicateFunction(formatted_raw_ostream &OS,
                              PredicateSet &Predicates, indent Indent) const;
   void emitDecoderFunction(formatted_raw_ostream &OS, DecoderSet &Decoders,
-                           indent Indent) const;
+                           StringRef SpecializedInsnType, indent Indent) const;
 
   // run - Output the code emitter
   void run(raw_ostream &o);
@@ -1068,24 +1085,35 @@ void DecoderEmitter::emitPredicateFunction(formatted_raw_ostream &OS,
 
 void DecoderEmitter::emitDecoderFunction(formatted_raw_ostream &OS,
                                          DecoderSet &Decoders,
+                                         StringRef SpecializedInsnType,
                                          indent Indent) const {
+  auto emitTemplate = [&OS, SpecializedInsnType, &Indent] {
+    if (SpecializedInsnType.empty())
+      OS << Indent << "template <typename InsnType>\n";
+  };
+
+  StringRef InsnType =
+      SpecializedInsnType.empty() ? "InsnType" : SpecializedInsnType;
+
   // The decoder function is just a big switch statement or a table of function
   // pointers based on the input decoder index.
 
   // TODO: When InsnType is large, using uint64_t limits all fields to 64 bits
   // It would be better for emitBinaryParser to use a 64-bit tmp whenever
   // possible but fall back to an InsnType-sized tmp for truly large fields.
-  StringRef TmpTypeDecl =
-      "using TmpType = std::conditional_t<std::is_integral<InsnType>::value, "
-      "InsnType, uint64_t>;\n";
-  StringRef DecodeParams =
-      "DecodeStatus S, InsnType insn, MCInst &MI, uint64_t Address, const "
-      "MCDisassembler *Decoder, bool &DecodeComplete";
+  auto TmpTypeDecl = formatv(
+      "using TmpType = std::conditional_t<std::is_integral<{0}>::value, {0}, "
+      "uint64_t>;\n",
+      InsnType);
+  auto DecodeParams =
+      formatv("DecodeStatus S, {} insn, MCInst &MI, uint64_t Address, const "
+              "MCDisassembler *Decoder, bool &DecodeComplete",
+              InsnType);
 
   if (UseFnTableInDecodeToMCInst) {
     // Emit a function for each case first.
     for (const auto &[Index, Decoder] : enumerate(Decoders)) {
-      OS << Indent << "template <typename InsnType>\n";
+      emitTemplate();
       OS << Indent << "DecodeStatus decodeFn" << Index << "(" << DecodeParams
          << ") {\n";
       Indent += 2;
@@ -1099,7 +1127,7 @@ void DecoderEmitter::emitDecoderFunction(formatted_raw_ostream &OS,
   }
 
   OS << Indent << "// Handling " << Decoders.size() << " cases.\n";
-  OS << Indent << "template <typename InsnType>\n";
+  emitTemplate();
   OS << Indent << "static DecodeStatus decodeToMCInst(unsigned Idx, "
      << DecodeParams << ") {\n";
   Indent += 2;
@@ -2535,6 +2563,70 @@ handleHwModesUnrelatedEncodings(const CodeGenInstruction *Instr,
   }
 }
 
+// Result of parsing a single `non-templated-decode-to-mcinst-type-spec` option.
+using BitwidthSet = SmallSet<unsigned, 4>;
+struct NonTemplatedTypeSpec {
+  StringRef Type;
+  BitwidthSet Bitwidths;
+};
+
+static SmallVector<NonTemplatedTypeSpec>
+parseNonTemplatedTypeSpec(BitwidthSet &InstrBitwidths) {
+  SmallVector<NonTemplatedTypeSpec> Parsed;
+  if (DecodeToMCInstTypeSpecs.empty()) {
+    // If no `non-templated-decode-to-mcinst-type-spec` option is specified,
+    // create a type-spec with empty values, which will trigger generation of
+    // a templated `decodeToMCInst`.
+    Parsed.emplace_back();
+    return Parsed;
+  }
+
+  Parsed.reserve(DecodeToMCInstTypeSpecs.size());
+  BitwidthSet OptionBitwidths;
+
+  for (StringRef TypeSpec : DecodeToMCInstTypeSpecs) {
+    BitwidthSet Bitwidths;
+    // Each `non-templated-decode-to-mcinst-type-spec` is of the form
+    // <type>:=<list of bitwidths>. Note, <type> can in general be a templated
+    // type, so using the token ":=" as a separator to allow many general C++
+    // types here.
+    auto [Type, ListOfBitWidths] = TypeSpec.split(":=");
+    if (Type.empty())
+      PrintFatalError("Invalid typespec: " + TypeSpec);
+
+    for (StringRef BwStr : split(ListOfBitWidths, ',')) {
+      unsigned Bitwidth;
+      if (BwStr.getAsInteger(10, Bitwidth))
+        PrintFatalError("Invalid bitwidth: " + BwStr + " in typespec " +
+                        TypeSpec);
+
+      if (!OptionBitwidths.insert(Bitwidth).second)
+        PrintFatalError("Bitwidth " + Twine(Bitwidth) + " already specified.");
+
+      if (!InstrBitwidths.contains(Bitwidth))
+        PrintFatalError(Twine("No instruction of Bitwidth ") + Twine(Bitwidth) +
+                        " supported.");
+
+      InstrBitwidths.erase(Bitwidth);
+      Bitwidths.insert(Bitwidth);
+    }
+
+    if (Bitwidths.empty())
+      PrintFatalError("No bitwidth specified in typespec " + TypeSpec);
+
+    Parsed.emplace_back(NonTemplatedTypeSpec{Type, Bitwidths});
+  }
+
+  if (!InstrBitwidths.empty()) {
+    PrintFatalError([&InstrBitwidths](raw_ostream &OS) {
+      OS << "Bitwidth(s) ";
+      llvm::interleaveComma(InstrBitwidths, OS);
+      OS << " missing in `non-templated-decode-to-mcinst-type-spec` options.";
+    });
+  }
+  return Parsed;
+}
+
 // Emits disassembler code for instruction decoding.
 void DecoderEmitter::run(raw_ostream &o) {
   formatted_raw_ostream OS(o);
@@ -2646,35 +2738,59 @@ namespace {
     }
   }
 
+  // Collect all allowed Bitwidths for instructions.
+  BitwidthSet InstrBitwidths;
+  for (const auto &[NSAndByteSize, _] : OpcMap) {
+    const unsigned Bitwidth = 8 * NSAndByteSize.second;
+    InstrBitwidths.insert(Bitwidth);
+  }
+  SmallVector<NonTemplatedTypeSpec> NonTemplatedTypeSpecs =
+      parseNonTemplatedTypeSpec(InstrBitwidths);
+
   DecoderTableInfo TableInfo;
   unsigned OpcodeMask = 0;
-  for (const auto &[NSAndByteSize, EncodingIDs] : OpcMap) {
-    const std::string &DecoderNamespace = NSAndByteSize.first;
-    const unsigned BitWidth = 8 * NSAndByteSize.second;
-    // Emit the decoder for this namespace+width combination.
-    FilterChooser FC(NumberedEncodings, EncodingIDs, Operands,
-                     IsVarLenInst ? MaxInstLen : BitWidth, this);
-
-    // The decode table is cleared for each top level decoder function. The
-    // predicates and decoders themselves, however, are shared across all
-    // decoders to give more opportunities for uniqueing.
-    TableInfo.Table.clear();
-    TableInfo.FixupStack.clear();
-    TableInfo.FixupStack.emplace_back();
-    FC.emitTableEntries(TableInfo);
-    // Any NumToSkip fixups in the top level scope can resolve to the
-    // OPC_Fail at the end of the table.
-    assert(TableInfo.FixupStack.size() == 1 && "fixup stack phasing error!");
-    // Resolve any NumToSkip fixups in the current scope.
-    resolveTableFixups(TableInfo.Table, TableInfo.FixupStack.back(),
-                       TableInfo.Table.size());
-    TableInfo.FixupStack.clear();
+  for (const auto &[NTType, NTBitwidths] : NonTemplatedTypeSpecs) {
+    // Reset the Decoders for each non-templated type.
+    TableInfo.Decoders.clear();
+
+    for (const auto &[NSAndByteSize, EncodingIDs] : OpcMap) {
+      const std::string &DecoderNamespace = NSAndByteSize.first;
+      const unsigned InstrBitwidth =
+          IsVarLenInst ? MaxInstLen : 8 * NSAndByteSize.second;
+
+      // Only handle instruction of the non-templated bitwidth size when
+      // non-templated bitwidth option is enabled.
+      if (!NTBitwidths.empty() && !NTBitwidths.contains(InstrBitwidth))
+        continue;
+
+      // Emit the decoder for this namespace+width combination.
+      FilterChooser FC(NumberedEncodings, EncodingIDs, Operands,
+                       IsVarLenInst ? MaxInstLen : InstrBitwidth, this);
+
+      // The decode table is cleared for each top level decoder function. The
+      // predicates and decoders themselves, however, are shared across all
+      // decoders to give more opportunities for uniqueing.
+      TableInfo.Table.clear();
+      TableInfo.FixupStack.clear();
+      TableInfo.FixupStack.emplace_back();
+      FC.emitTableEntries(TableInfo);
+      // Any NumToSkip fixups in the top level scope can resolve to the
+      // OPC_Fail at the end of the table.
+      assert(TableInfo.FixupStack.size() == 1 && "fixup stack phasing error!");
+      // Resolve any NumToSkip fixups in the current scope.
+      resolveTableFixups(TableInfo.Table, TableInfo.FixupStack.back(),
+                         TableInfo.Table.size());
+      TableInfo.FixupStack.clear();
 
-    TableInfo.Table.push_back(MCD::OPC_Fail);
+      TableInfo.Table.push_back(MCD::OPC_Fail);
 
-    // Print the table to the output stream.
-    OpcodeMask |= emitTable(OS, TableInfo.Table, indent(0), FC.getBitWidth(),
-                            DecoderNamespace, EncodingIDs);
+      // Print the table to the output stream.
+      OpcodeMask |= emitTable(OS, TableInfo.Table, indent(0), FC.getBitWidth(),
+                              DecoderNamespace, EncodingIDs);
+    }
+
+    // Emit the decoder function for this BitWidth.
+    emitDecoderFunction(OS, TableInfo.Decoders, NTType, indent(0));
   }
 
   // For variable instruction, we emit a instruction length table
@@ -2691,9 +2807,6 @@ namespace {
   if (HasCheckPredicate)
     emitPredicateFunction(OS, TableInfo.Predicates, indent(0));
 
-  // Emit the decoder function.
-  emitDecoderFunction(OS, TableInfo.Decoders, indent(0));
-
   // Emit the main entry point for the decoder, decodeInstruction().
   emitDecodeInstruction(OS, IsVarLenInst, OpcodeMask);
 

>From 2b778f2dd25d06ef71e9003a1acd1dff7d75aa0e Mon Sep 17 00:00:00 2001
From: Rahul Joshi <rjoshi at nvidia.com>
Date: Wed, 2 Jul 2025 06:53:54 -0700
Subject: [PATCH 2/7] Review feedback

---
 llvm/include/llvm/TableGen/Record.h      |   2 +
 llvm/include/llvm/Target/Target.td       |  19 ++++
 llvm/lib/TableGen/Record.cpp             |  43 +++++-----
 llvm/lib/Target/AArch64/AArch64.td       |   6 +-
 llvm/lib/Target/AArch64/CMakeLists.txt   |   3 +-
 llvm/lib/Target/AMDGPU/CMakeLists.txt    |   5 +-
 llvm/lib/Target/ARC/CMakeLists.txt       |   4 +-
 llvm/lib/Target/ARM/CMakeLists.txt       |   4 +-
 llvm/lib/Target/AVR/CMakeLists.txt       |   3 +-
 llvm/lib/Target/BPF/CMakeLists.txt       |   3 +-
 llvm/lib/Target/CSKY/CMakeLists.txt      |   3 +-
 llvm/lib/Target/Hexagon/CMakeLists.txt   |   3 +-
 llvm/lib/Target/Lanai/CMakeLists.txt     |   3 +-
 llvm/lib/Target/LoongArch/CMakeLists.txt |   3 +-
 llvm/lib/Target/MSP430/CMakeLists.txt    |   3 +-
 llvm/lib/Target/Mips/CMakeLists.txt      |   3 +-
 llvm/lib/Target/PowerPC/CMakeLists.txt   |   3 +-
 llvm/lib/Target/RISCV/CMakeLists.txt     |   4 +-
 llvm/lib/Target/RISCV/RISCV.td           |   4 +
 llvm/lib/Target/Sparc/CMakeLists.txt     |   3 +-
 llvm/lib/Target/SystemZ/CMakeLists.txt   |   3 +-
 llvm/lib/Target/VE/CMakeLists.txt        |   3 +-
 llvm/lib/Target/XCore/CMakeLists.txt     |   4 +-
 llvm/lib/Target/Xtensa/CMakeLists.txt    |   3 +-
 llvm/utils/TableGen/DecoderEmitter.cpp   | 105 +++++++++++------------
 25 files changed, 120 insertions(+), 122 deletions(-)

diff --git a/llvm/include/llvm/TableGen/Record.h b/llvm/include/llvm/TableGen/Record.h
index a2b86eb8e7cad..d571710781d83 100644
--- a/llvm/include/llvm/TableGen/Record.h
+++ b/llvm/include/llvm/TableGen/Record.h
@@ -803,6 +803,8 @@ class ListInit final : public TypedInit,
   size_t size() const { return NumElements; }
   bool empty() const { return NumElements == 0; }
 
+  std::vector<int64_t> getAsListOfInts() const;
+
   const Init *getBit(unsigned Bit) const override {
     llvm_unreachable("Illegal bit reference off list");
   }
diff --git a/llvm/include/llvm/Target/Target.td b/llvm/include/llvm/Target/Target.td
index 4c83f8a580aa0..bef483d301235 100644
--- a/llvm/include/llvm/Target/Target.td
+++ b/llvm/include/llvm/Target/Target.td
@@ -1158,6 +1158,25 @@ class InstrInfo {
   //
   // This option is a temporary migration help. It will go away.
   bit guessInstructionProperties = true;
+
+  // These properties, when set, opt into the non-templated variants of
+  // `decodeToMCInst` generated by TableGen DecoderEmitter backend. Using this
+  // option helps reduce the code size of the generated code as compared to the
+  // templated `decodeToMCInst` that is generated by default.
+  // For each index `I`, InsnCPPTypes[I] is a C++ type that will be used to
+  // generate a non-templated `decodeToMCInst`, and InstBitwidths[I] is a list
+  // instruction bitwidth(s) whose decoders will be included in the generated
+  // code.
+  list<string> InsnCPPTypes = [];
+  list<list<int>> InsnBitwidths = [];
+  assert !eq(!size(InsnCPPTypes), !size(InsnBitwidths)),
+     "The InsnCPPTypes and InsnBitwidths lists must be the same length";
+
+  // Make sure the InstCPPTypes, if not empty, does not contain empty strings.
+  assert !or(!empty(InsnCPPTypes), !empty(!filter(e, InsnCPPTypes, !empty(e)))),
+     "Entries in InstCPPTypes cannot be empty";
+
+  // Make sure that InsnBitwidths, if not empty, does not contain empty list.
 }
 
 // Standard Pseudo Instructions.
diff --git a/llvm/lib/TableGen/Record.cpp b/llvm/lib/TableGen/Record.cpp
index 1f3e5dc68f1d6..8106609c8fa68 100644
--- a/llvm/lib/TableGen/Record.cpp
+++ b/llvm/lib/TableGen/Record.cpp
@@ -804,6 +804,15 @@ std::string ListInit::getAsString() const {
   return Result + "]";
 }
 
+std::vector<int64_t> ListInit::getAsListOfInts() const {
+  if (!isa<IntRecTy>(getElementType()))
+    PrintFatalError("List does not contain integer values");
+  std::vector<int64_t> Ints;
+  for (const Init *I : getElements())
+    Ints.push_back(cast<IntInit>(I)->getValue());
+  return Ints;
+}
+
 const Init *OpInit::getBit(unsigned Bit) const {
   if (getType() == BitRecTy::get(getRecordKeeper()))
     return this;
@@ -3119,32 +3128,26 @@ int64_t Record::getValueAsInt(StringRef FieldName) const {
 std::vector<int64_t>
 Record::getValueAsListOfInts(StringRef FieldName) const {
   const ListInit *List = getValueAsListInit(FieldName);
-  std::vector<int64_t> Ints;
-  for (const Init *I : List->getElements()) {
-    if (const auto *II = dyn_cast<IntInit>(I))
-      Ints.push_back(II->getValue());
-    else
-      PrintFatalError(getLoc(),
-                      Twine("Record `") + getName() + "', field `" + FieldName +
-                          "' exists but does not have a list of ints value: " +
-                          I->getAsString());
-  }
-  return Ints;
+  if (!isa<IntRecTy>(List->getElementType()))
+    PrintFatalError(getLoc(),
+                    Twine("Record `") + getName() + "', field `" + FieldName +
+                        "' exists but does not have a list of ints value: " +
+                        List->getAsString());
+  return List->getAsListOfInts();
 }
 
 std::vector<StringRef>
 Record::getValueAsListOfStrings(StringRef FieldName) const {
   const ListInit *List = getValueAsListInit(FieldName);
+  if (!isa<StringRecTy>(List->getElementType()))
+    PrintFatalError(getLoc(),
+                    Twine("Record `") + getName() + "', field `" + FieldName +
+                        "' exists but does not have a list of string value: " +
+                        List->getAsString());
+
   std::vector<StringRef> Strings;
-  for (const Init *I : List->getElements()) {
-    if (const auto *SI = dyn_cast<StringInit>(I))
-      Strings.push_back(SI->getValue());
-    else
-      PrintFatalError(getLoc(),
-                      Twine("Record `") + getName() + "', field `" + FieldName +
-                          "' exists but does not have a list of strings value: " +
-                          I->getAsString());
-  }
+  for (const Init *I : List->getElements())
+    Strings.push_back(cast<StringInit>(I)->getValue());
   return Strings;
 }
 
diff --git a/llvm/lib/Target/AArch64/AArch64.td b/llvm/lib/Target/AArch64/AArch64.td
index 86f95488e6bb7..3e8cabf3cb9ca 100644
--- a/llvm/lib/Target/AArch64/AArch64.td
+++ b/llvm/lib/Target/AArch64/AArch64.td
@@ -40,7 +40,11 @@ include "AArch64SchedPredExynos.td"
 include "AArch64SchedPredNeoverse.td"
 include "AArch64Combine.td"
 
-def AArch64InstrInfo : InstrInfo;
+def AArch64InstrInfo : InstrInfo {
+  // Opt-in into non-templated code for instruction decoder.
+  let InsnCPPTypes = ["uint32_t"];
+  let InsnBitwidths = [[32]];
+}
 
 //===----------------------------------------------------------------------===//
 // Named operands for MRS/MSR/TLBI/...
diff --git a/llvm/lib/Target/AArch64/CMakeLists.txt b/llvm/lib/Target/AArch64/CMakeLists.txt
index 98cc8693144f0..66136a464f05d 100644
--- a/llvm/lib/Target/AArch64/CMakeLists.txt
+++ b/llvm/lib/Target/AArch64/CMakeLists.txt
@@ -7,8 +7,7 @@ tablegen(LLVM AArch64GenAsmWriter.inc -gen-asm-writer)
 tablegen(LLVM AArch64GenAsmWriter1.inc -gen-asm-writer -asmwriternum=1)
 tablegen(LLVM AArch64GenCallingConv.inc -gen-callingconv)
 tablegen(LLVM AArch64GenDAGISel.inc -gen-dag-isel)
-tablegen(LLVM AArch64GenDisassemblerTables.inc -gen-disassembler
-              -non-templated-decode-to-mcinst-type-spec=uint32_t:=32)
+tablegen(LLVM AArch64GenDisassemblerTables.inc -gen-disassembler)
 tablegen(LLVM AArch64GenFastISel.inc -gen-fast-isel)
 tablegen(LLVM AArch64GenGlobalISel.inc -gen-global-isel)
 tablegen(LLVM AArch64GenO0PreLegalizeGICombiner.inc -gen-global-isel-combiner
diff --git a/llvm/lib/Target/AMDGPU/CMakeLists.txt b/llvm/lib/Target/AMDGPU/CMakeLists.txt
index 6254750c10c3c..e3519f192137c 100644
--- a/llvm/lib/Target/AMDGPU/CMakeLists.txt
+++ b/llvm/lib/Target/AMDGPU/CMakeLists.txt
@@ -6,10 +6,7 @@ tablegen(LLVM AMDGPUGenAsmMatcher.inc -gen-asm-matcher)
 tablegen(LLVM AMDGPUGenAsmWriter.inc -gen-asm-writer)
 tablegen(LLVM AMDGPUGenCallingConv.inc -gen-callingconv)
 tablegen(LLVM AMDGPUGenDAGISel.inc -gen-dag-isel)
-tablegen(LLVM AMDGPUGenDisassemblerTables.inc -gen-disassembler
-         -non-templated-decode-to-mcinst-type-spec=uint32_t:=32
-         -non-templated-decode-to-mcinst-type-spec=uint64_t:=64
-         -non-templated-decode-to-mcinst-type-spec=DecoderUInt128:=96,128)
+tablegen(LLVM AMDGPUGenDisassemblerTables.inc -gen-disassembler)
 tablegen(LLVM AMDGPUGenInstrInfo.inc -gen-instr-info)
 tablegen(LLVM AMDGPUGenMCCodeEmitter.inc -gen-emitter)
 tablegen(LLVM AMDGPUGenMCPseudoLowering.inc -gen-pseudo-lowering)
diff --git a/llvm/lib/Target/ARC/CMakeLists.txt b/llvm/lib/Target/ARC/CMakeLists.txt
index e6656576fbcc3..196cc31cc5080 100644
--- a/llvm/lib/Target/ARC/CMakeLists.txt
+++ b/llvm/lib/Target/ARC/CMakeLists.txt
@@ -5,9 +5,7 @@ set(LLVM_TARGET_DEFINITIONS ARC.td)
 tablegen(LLVM ARCGenAsmWriter.inc -gen-asm-writer)
 tablegen(LLVM ARCGenCallingConv.inc -gen-callingconv)
 tablegen(LLVM ARCGenDAGISel.inc -gen-dag-isel)
-tablegen(LLVM ARCGenDisassemblerTables.inc -gen-disassembler
-         -non-templated-decode-to-mcinst-type-spec=uint32_t:=16,32
-         -non-templated-decode-to-mcinst-type-spec=uint64_t:=48,64)
+tablegen(LLVM ARCGenDisassemblerTables.inc -gen-disassembler)
 tablegen(LLVM ARCGenInstrInfo.inc -gen-instr-info)
 tablegen(LLVM ARCGenRegisterInfo.inc -gen-register-info)
 tablegen(LLVM ARCGenSDNodeInfo.inc -gen-sd-node-info)
diff --git a/llvm/lib/Target/ARM/CMakeLists.txt b/llvm/lib/Target/ARM/CMakeLists.txt
index 718a084ec6388..a39629bd8aeb0 100644
--- a/llvm/lib/Target/ARM/CMakeLists.txt
+++ b/llvm/lib/Target/ARM/CMakeLists.txt
@@ -6,9 +6,7 @@ tablegen(LLVM ARMGenAsmMatcher.inc -gen-asm-matcher)
 tablegen(LLVM ARMGenAsmWriter.inc -gen-asm-writer)
 tablegen(LLVM ARMGenCallingConv.inc -gen-callingconv)
 tablegen(LLVM ARMGenDAGISel.inc -gen-dag-isel)
-tablegen(LLVM ARMGenDisassemblerTables.inc -gen-disassembler
-         -non-templated-decode-to-mcinst-type-spec=uint16_t:=16
-         -non-templated-decode-to-mcinst-type-spec=uint32_t:=32)
+tablegen(LLVM ARMGenDisassemblerTables.inc -gen-disassembler)
 tablegen(LLVM ARMGenFastISel.inc -gen-fast-isel)
 tablegen(LLVM ARMGenGlobalISel.inc -gen-global-isel)
 tablegen(LLVM ARMGenInstrInfo.inc -gen-instr-info)
diff --git a/llvm/lib/Target/AVR/CMakeLists.txt b/llvm/lib/Target/AVR/CMakeLists.txt
index a2da85d77a325..781dac02c7083 100644
--- a/llvm/lib/Target/AVR/CMakeLists.txt
+++ b/llvm/lib/Target/AVR/CMakeLists.txt
@@ -6,8 +6,7 @@ tablegen(LLVM AVRGenAsmMatcher.inc -gen-asm-matcher)
 tablegen(LLVM AVRGenAsmWriter.inc -gen-asm-writer)
 tablegen(LLVM AVRGenCallingConv.inc -gen-callingconv)
 tablegen(LLVM AVRGenDAGISel.inc -gen-dag-isel)
-tablegen(LLVM AVRGenDisassemblerTables.inc -gen-disassembler
-         -non-templated-decode-to-mcinst-type-spec=uint32_t:=16,32)
+tablegen(LLVM AVRGenDisassemblerTables.inc -gen-disassembler)
 tablegen(LLVM AVRGenInstrInfo.inc -gen-instr-info)
 tablegen(LLVM AVRGenMCCodeEmitter.inc -gen-emitter)
 tablegen(LLVM AVRGenRegisterInfo.inc -gen-register-info)
diff --git a/llvm/lib/Target/BPF/CMakeLists.txt b/llvm/lib/Target/BPF/CMakeLists.txt
index 6a609d645dfa1..eade4cacb7100 100644
--- a/llvm/lib/Target/BPF/CMakeLists.txt
+++ b/llvm/lib/Target/BPF/CMakeLists.txt
@@ -6,8 +6,7 @@ tablegen(LLVM BPFGenAsmMatcher.inc -gen-asm-matcher)
 tablegen(LLVM BPFGenAsmWriter.inc -gen-asm-writer)
 tablegen(LLVM BPFGenCallingConv.inc -gen-callingconv)
 tablegen(LLVM BPFGenDAGISel.inc -gen-dag-isel)
-tablegen(LLVM BPFGenDisassemblerTables.inc -gen-disassembler
-              -non-templated-decode-to-mcinst-type-spec=uint64_t:=64)
+tablegen(LLVM BPFGenDisassemblerTables.inc -gen-disassembler)
 tablegen(LLVM BPFGenInstrInfo.inc -gen-instr-info)
 tablegen(LLVM BPFGenMCCodeEmitter.inc -gen-emitter)
 tablegen(LLVM BPFGenRegisterInfo.inc -gen-register-info)
diff --git a/llvm/lib/Target/CSKY/CMakeLists.txt b/llvm/lib/Target/CSKY/CMakeLists.txt
index eadf0169edef1..4b900bc99c271 100644
--- a/llvm/lib/Target/CSKY/CMakeLists.txt
+++ b/llvm/lib/Target/CSKY/CMakeLists.txt
@@ -7,8 +7,7 @@ tablegen(LLVM CSKYGenAsmWriter.inc -gen-asm-writer)
 tablegen(LLVM CSKYGenCallingConv.inc -gen-callingconv)
 tablegen(LLVM CSKYGenCompressInstEmitter.inc -gen-compress-inst-emitter)
 tablegen(LLVM CSKYGenDAGISel.inc -gen-dag-isel)
-tablegen(LLVM CSKYGenDisassemblerTables.inc -gen-disassembler
-              -non-templated-decode-to-mcinst-type-spec=uint32_t:=16,32)
+tablegen(LLVM CSKYGenDisassemblerTables.inc -gen-disassembler)
 tablegen(LLVM CSKYGenInstrInfo.inc -gen-instr-info)
 tablegen(LLVM CSKYGenMCCodeEmitter.inc -gen-emitter)
 tablegen(LLVM CSKYGenMCPseudoLowering.inc -gen-pseudo-lowering)
diff --git a/llvm/lib/Target/Hexagon/CMakeLists.txt b/llvm/lib/Target/Hexagon/CMakeLists.txt
index be2bc89155612..d758260a8ab5d 100644
--- a/llvm/lib/Target/Hexagon/CMakeLists.txt
+++ b/llvm/lib/Target/Hexagon/CMakeLists.txt
@@ -7,8 +7,7 @@ tablegen(LLVM HexagonGenAsmWriter.inc -gen-asm-writer)
 tablegen(LLVM HexagonGenCallingConv.inc -gen-callingconv)
 tablegen(LLVM HexagonGenDAGISel.inc -gen-dag-isel)
 tablegen(LLVM HexagonGenDFAPacketizer.inc -gen-dfa-packetizer)
-tablegen(LLVM HexagonGenDisassemblerTables.inc -gen-disassembler
-              -non-templated-decode-to-mcinst-type-spec=uint32_t:=32)
+tablegen(LLVM HexagonGenDisassemblerTables.inc -gen-disassembler)
 tablegen(LLVM HexagonGenInstrInfo.inc -gen-instr-info)
 tablegen(LLVM HexagonGenMCCodeEmitter.inc -gen-emitter)
 tablegen(LLVM HexagonGenRegisterInfo.inc -gen-register-info)
diff --git a/llvm/lib/Target/Lanai/CMakeLists.txt b/llvm/lib/Target/Lanai/CMakeLists.txt
index dfb0c93e1a5e3..4a628e13fc177 100644
--- a/llvm/lib/Target/Lanai/CMakeLists.txt
+++ b/llvm/lib/Target/Lanai/CMakeLists.txt
@@ -6,8 +6,7 @@ tablegen(LLVM LanaiGenAsmMatcher.inc -gen-asm-matcher)
 tablegen(LLVM LanaiGenAsmWriter.inc -gen-asm-writer)
 tablegen(LLVM LanaiGenCallingConv.inc -gen-callingconv)
 tablegen(LLVM LanaiGenDAGISel.inc -gen-dag-isel)
-tablegen(LLVM LanaiGenDisassemblerTables.inc -gen-disassembler
-              -non-templated-decode-to-mcinst-type-spec=uint32_t:=32)
+tablegen(LLVM LanaiGenDisassemblerTables.inc -gen-disassembler)
 tablegen(LLVM LanaiGenInstrInfo.inc -gen-instr-info)
 tablegen(LLVM LanaiGenMCCodeEmitter.inc -gen-emitter)
 tablegen(LLVM LanaiGenRegisterInfo.inc -gen-register-info)
diff --git a/llvm/lib/Target/LoongArch/CMakeLists.txt b/llvm/lib/Target/LoongArch/CMakeLists.txt
index c851f5c2fc1da..0f674b1b0fa9e 100644
--- a/llvm/lib/Target/LoongArch/CMakeLists.txt
+++ b/llvm/lib/Target/LoongArch/CMakeLists.txt
@@ -5,8 +5,7 @@ set(LLVM_TARGET_DEFINITIONS LoongArch.td)
 tablegen(LLVM LoongArchGenAsmMatcher.inc -gen-asm-matcher)
 tablegen(LLVM LoongArchGenAsmWriter.inc -gen-asm-writer)
 tablegen(LLVM LoongArchGenDAGISel.inc -gen-dag-isel)
-tablegen(LLVM LoongArchGenDisassemblerTables.inc -gen-disassembler
-              -non-templated-decode-to-mcinst-type-spec=uint32_t:=32)
+tablegen(LLVM LoongArchGenDisassemblerTables.inc -gen-disassembler)
 tablegen(LLVM LoongArchGenInstrInfo.inc -gen-instr-info)
 tablegen(LLVM LoongArchGenMCPseudoLowering.inc -gen-pseudo-lowering)
 tablegen(LLVM LoongArchGenMCCodeEmitter.inc -gen-emitter)
diff --git a/llvm/lib/Target/MSP430/CMakeLists.txt b/llvm/lib/Target/MSP430/CMakeLists.txt
index f10c8192e7df0..4081d3472fd78 100644
--- a/llvm/lib/Target/MSP430/CMakeLists.txt
+++ b/llvm/lib/Target/MSP430/CMakeLists.txt
@@ -6,8 +6,7 @@ tablegen(LLVM MSP430GenAsmMatcher.inc -gen-asm-matcher)
 tablegen(LLVM MSP430GenAsmWriter.inc -gen-asm-writer)
 tablegen(LLVM MSP430GenCallingConv.inc -gen-callingconv)
 tablegen(LLVM MSP430GenDAGISel.inc -gen-dag-isel)
-tablegen(LLVM MSP430GenDisassemblerTables.inc -gen-disassembler
-              -non-templated-decode-to-mcinst-type-spec=uint64_t:=16,32,48)
+tablegen(LLVM MSP430GenDisassemblerTables.inc -gen-disassembler)
 tablegen(LLVM MSP430GenInstrInfo.inc -gen-instr-info)
 tablegen(LLVM MSP430GenMCCodeEmitter.inc -gen-emitter)
 tablegen(LLVM MSP430GenRegisterInfo.inc -gen-register-info)
diff --git a/llvm/lib/Target/Mips/CMakeLists.txt b/llvm/lib/Target/Mips/CMakeLists.txt
index 2516d00706a91..21d1765107ae6 100644
--- a/llvm/lib/Target/Mips/CMakeLists.txt
+++ b/llvm/lib/Target/Mips/CMakeLists.txt
@@ -6,8 +6,7 @@ tablegen(LLVM MipsGenAsmMatcher.inc -gen-asm-matcher)
 tablegen(LLVM MipsGenAsmWriter.inc -gen-asm-writer)
 tablegen(LLVM MipsGenCallingConv.inc -gen-callingconv)
 tablegen(LLVM MipsGenDAGISel.inc -gen-dag-isel)
-tablegen(LLVM MipsGenDisassemblerTables.inc -gen-disassembler
-              -non-templated-decode-to-mcinst-type-spec=uint32_t:=16,32)
+tablegen(LLVM MipsGenDisassemblerTables.inc -gen-disassembler)
 tablegen(LLVM MipsGenFastISel.inc -gen-fast-isel)
 tablegen(LLVM MipsGenGlobalISel.inc -gen-global-isel)
 tablegen(LLVM MipsGenPostLegalizeGICombiner.inc -gen-global-isel-combiner
diff --git a/llvm/lib/Target/PowerPC/CMakeLists.txt b/llvm/lib/Target/PowerPC/CMakeLists.txt
index 136db0634eb93..3808a26a0b92a 100644
--- a/llvm/lib/Target/PowerPC/CMakeLists.txt
+++ b/llvm/lib/Target/PowerPC/CMakeLists.txt
@@ -6,8 +6,7 @@ tablegen(LLVM PPCGenAsmMatcher.inc -gen-asm-matcher)
 tablegen(LLVM PPCGenAsmWriter.inc -gen-asm-writer)
 tablegen(LLVM PPCGenCallingConv.inc -gen-callingconv)
 tablegen(LLVM PPCGenDAGISel.inc -gen-dag-isel)
-tablegen(LLVM PPCGenDisassemblerTables.inc -gen-disassembler
-               -non-templated-decode-to-mcinst-type-spec=uint64_t:=32,64)
+tablegen(LLVM PPCGenDisassemblerTables.inc -gen-disassembler)
 tablegen(LLVM PPCGenFastISel.inc -gen-fast-isel)
 tablegen(LLVM PPCGenInstrInfo.inc -gen-instr-info)
 tablegen(LLVM PPCGenMCCodeEmitter.inc -gen-emitter)
diff --git a/llvm/lib/Target/RISCV/CMakeLists.txt b/llvm/lib/Target/RISCV/CMakeLists.txt
index 9df6701387d43..e32d6eab3b977 100644
--- a/llvm/lib/Target/RISCV/CMakeLists.txt
+++ b/llvm/lib/Target/RISCV/CMakeLists.txt
@@ -7,9 +7,7 @@ tablegen(LLVM RISCVGenAsmWriter.inc -gen-asm-writer)
 tablegen(LLVM RISCVGenCompressInstEmitter.inc -gen-compress-inst-emitter)
 tablegen(LLVM RISCVGenMacroFusion.inc -gen-macro-fusion-pred)
 tablegen(LLVM RISCVGenDAGISel.inc -gen-dag-isel)
-tablegen(LLVM RISCVGenDisassemblerTables.inc -gen-disassembler
-              -non-templated-decode-to-mcinst-type-spec=uint32_t:=16,32
-              -non-templated-decode-to-mcinst-type-spec=uint64_t:=48)
+tablegen(LLVM RISCVGenDisassemblerTables.inc -gen-disassembler)
 tablegen(LLVM RISCVGenInstrInfo.inc -gen-instr-info)
 tablegen(LLVM RISCVGenMCCodeEmitter.inc -gen-emitter)
 tablegen(LLVM RISCVGenMCPseudoLowering.inc -gen-pseudo-lowering)
diff --git a/llvm/lib/Target/RISCV/RISCV.td b/llvm/lib/Target/RISCV/RISCV.td
index b24d8637cb27f..b3ce392d27a17 100644
--- a/llvm/lib/Target/RISCV/RISCV.td
+++ b/llvm/lib/Target/RISCV/RISCV.td
@@ -85,6 +85,10 @@ include "RISCVPfmCounters.td"
 
 def RISCVInstrInfo : InstrInfo {
   let guessInstructionProperties = 0;
+
+  // Opt-in into non-templated code for instruction decoder.
+  let InsnCPPTypes = ["uint64_t"];
+  let InsnBitwidths = [[16, 32, 48]];
 }
 
 def RISCVAsmParser : AsmParser {
diff --git a/llvm/lib/Target/Sparc/CMakeLists.txt b/llvm/lib/Target/Sparc/CMakeLists.txt
index 6334dbbc6cc1a..f682719ac483f 100644
--- a/llvm/lib/Target/Sparc/CMakeLists.txt
+++ b/llvm/lib/Target/Sparc/CMakeLists.txt
@@ -6,8 +6,7 @@ tablegen(LLVM SparcGenAsmMatcher.inc -gen-asm-matcher)
 tablegen(LLVM SparcGenAsmWriter.inc -gen-asm-writer)
 tablegen(LLVM SparcGenCallingConv.inc -gen-callingconv)
 tablegen(LLVM SparcGenDAGISel.inc -gen-dag-isel)
-tablegen(LLVM SparcGenDisassemblerTables.inc -gen-disassembler
-               -non-templated-decode-to-mcinst-type-spec=uint32_t:=32)
+tablegen(LLVM SparcGenDisassemblerTables.inc -gen-disassembler)
 tablegen(LLVM SparcGenInstrInfo.inc -gen-instr-info)
 tablegen(LLVM SparcGenMCCodeEmitter.inc -gen-emitter)
 tablegen(LLVM SparcGenRegisterInfo.inc -gen-register-info)
diff --git a/llvm/lib/Target/SystemZ/CMakeLists.txt b/llvm/lib/Target/SystemZ/CMakeLists.txt
index 1caeef468f3fb..0d8f3eac6ee4f 100644
--- a/llvm/lib/Target/SystemZ/CMakeLists.txt
+++ b/llvm/lib/Target/SystemZ/CMakeLists.txt
@@ -7,8 +7,7 @@ tablegen(LLVM SystemZGenGNUAsmWriter.inc -gen-asm-writer)
 tablegen(LLVM SystemZGenHLASMAsmWriter.inc -gen-asm-writer -asmwriternum=1)
 tablegen(LLVM SystemZGenCallingConv.inc -gen-callingconv)
 tablegen(LLVM SystemZGenDAGISel.inc -gen-dag-isel)
-tablegen(LLVM SystemZGenDisassemblerTables.inc -gen-disassembler
-               -non-templated-decode-to-mcinst-type-spec=uint64_t:=16,32,48)
+tablegen(LLVM SystemZGenDisassemblerTables.inc -gen-disassembler)
 tablegen(LLVM SystemZGenInstrInfo.inc -gen-instr-info)
 tablegen(LLVM SystemZGenMCCodeEmitter.inc -gen-emitter)
 tablegen(LLVM SystemZGenRegisterInfo.inc -gen-register-info)
diff --git a/llvm/lib/Target/VE/CMakeLists.txt b/llvm/lib/Target/VE/CMakeLists.txt
index 6b83a3e7ae28e..d1bb4f32fcba7 100644
--- a/llvm/lib/Target/VE/CMakeLists.txt
+++ b/llvm/lib/Target/VE/CMakeLists.txt
@@ -4,8 +4,7 @@ set(LLVM_TARGET_DEFINITIONS VE.td)
 
 tablegen(LLVM VEGenRegisterInfo.inc -gen-register-info)
 tablegen(LLVM VEGenInstrInfo.inc -gen-instr-info)
-tablegen(LLVM VEGenDisassemblerTables.inc -gen-disassembler
-               -non-templated-decode-to-mcinst-type-spec=uint64_t:=64)
+tablegen(LLVM VEGenDisassemblerTables.inc -gen-disassembler)
 tablegen(LLVM VEGenMCCodeEmitter.inc -gen-emitter)
 tablegen(LLVM VEGenAsmWriter.inc -gen-asm-writer)
 tablegen(LLVM VEGenAsmMatcher.inc -gen-asm-matcher)
diff --git a/llvm/lib/Target/XCore/CMakeLists.txt b/llvm/lib/Target/XCore/CMakeLists.txt
index 3b5bf848d8144..f411c658b43b0 100644
--- a/llvm/lib/Target/XCore/CMakeLists.txt
+++ b/llvm/lib/Target/XCore/CMakeLists.txt
@@ -5,9 +5,7 @@ set(LLVM_TARGET_DEFINITIONS XCore.td)
 tablegen(LLVM XCoreGenAsmWriter.inc -gen-asm-writer)
 tablegen(LLVM XCoreGenCallingConv.inc -gen-callingconv)
 tablegen(LLVM XCoreGenDAGISel.inc -gen-dag-isel)
-tablegen(LLVM XCoreGenDisassemblerTables.inc -gen-disassembler
-          -non-templated-decode-to-mcinst-type-spec=uint16_t:=16
-          -non-templated-decode-to-mcinst-type-spec=uint32_t:=32)
+tablegen(LLVM XCoreGenDisassemblerTables.inc -gen-disassembler)
 tablegen(LLVM XCoreGenInstrInfo.inc -gen-instr-info)
 tablegen(LLVM XCoreGenRegisterInfo.inc -gen-register-info)
 tablegen(LLVM XCoreGenSDNodeInfo.inc -gen-sd-node-info)
diff --git a/llvm/lib/Target/Xtensa/CMakeLists.txt b/llvm/lib/Target/Xtensa/CMakeLists.txt
index 9c825b5d880c7..4fc1ba6dfa650 100644
--- a/llvm/lib/Target/Xtensa/CMakeLists.txt
+++ b/llvm/lib/Target/Xtensa/CMakeLists.txt
@@ -6,8 +6,7 @@ tablegen(LLVM XtensaGenAsmMatcher.inc -gen-asm-matcher)
 tablegen(LLVM XtensaGenAsmWriter.inc -gen-asm-writer)
 tablegen(LLVM XtensaGenCallingConv.inc -gen-callingconv)
 tablegen(LLVM XtensaGenDAGISel.inc -gen-dag-isel)
-tablegen(LLVM XtensaGenDisassemblerTables.inc -gen-disassembler
-               -non-templated-decode-to-mcinst-type-spec=uint64_t:=16,24)
+tablegen(LLVM XtensaGenDisassemblerTables.inc -gen-disassembler)
 tablegen(LLVM XtensaGenInstrInfo.inc -gen-instr-info)
 tablegen(LLVM XtensaGenMCCodeEmitter.inc -gen-emitter)
 tablegen(LLVM XtensaGenRegisterInfo.inc -gen-register-info)
diff --git a/llvm/utils/TableGen/DecoderEmitter.cpp b/llvm/utils/TableGen/DecoderEmitter.cpp
index fb51bd90fa961..a8cf90a162903 100644
--- a/llvm/utils/TableGen/DecoderEmitter.cpp
+++ b/llvm/utils/TableGen/DecoderEmitter.cpp
@@ -93,22 +93,6 @@ static cl::opt<bool> UseFnTableInDecodeToMCInst(
         "of the generated code."),
     cl::init(false), cl::cat(DisassemblerEmitterCat));
 
-// Option to generate a non-templated version of `decodeToMCInst`. The
-// templated `decodeToMCInst` is templated on `InsnType` and a given `InsnType`
-// can target instructions with one or more Bitwidths. So the option to
-// generate a non-templated `decodeToMCInst` is a typespec of the form
-// type::=list-of-sizes.
-
-// For example, for the AMDGPU target, the type `DecoderUInt128` is used for
-// both 96 and 128 bit instructions. So the generated non-templated
-// `decodeToMCInst` will support decoding both these instruction Bitwidths and
-// the option will be DecoderUInt128::=96,128
-static cl::list<std::string> DecodeToMCInstTypeSpecs(
-    "non-templated-decode-to-mcinst-type-spec",
-    cl::desc("list of C++ types and associated bitwidths to used to generate "
-             "non-templated `decodeToMCInst`."),
-    cl::cat(DisassemblerEmitterCat));
-
 STATISTIC(NumEncodings, "Number of encodings considered");
 STATISTIC(NumEncodingsLackingDisasm,
           "Number of encodings without disassembler info");
@@ -233,6 +217,14 @@ struct EncodingIDAndOpcode {
 using EncodingIDsVec = std::vector<EncodingIDAndOpcode>;
 using NamespacesHwModesMap = std::map<std::string, std::set<StringRef>>;
 
+// Result of parsing the `InsnCPPTypes` and `InstBitwidths` fields in the Target
+// instruction set.
+using BitwidthSet = SmallSet<unsigned, 4>;
+struct NonTemplatedInsnType {
+  StringRef CPPType;
+  BitwidthSet Bitwidths;
+};
+
 class DecoderEmitter {
   const RecordKeeper &RK;
   std::vector<EncodingAndInst> NumberedEncodings;
@@ -257,6 +249,8 @@ class DecoderEmitter {
   void run(raw_ostream &o);
 
 private:
+  SmallVector<NonTemplatedInsnType>
+  parseNonTemplatedInsnTypes(BitwidthSet &InstrBitwidths);
   CodeGenTarget Target;
 
 public:
@@ -2562,66 +2556,63 @@ handleHwModesUnrelatedEncodings(const CodeGenInstruction *Instr,
     break;
   }
 }
+SmallVector<NonTemplatedInsnType>
+DecoderEmitter::parseNonTemplatedInsnTypes(BitwidthSet &InstrBitwidths) {
+  SmallVector<NonTemplatedInsnType> Parsed;
 
-// Result of parsing a single `non-templated-decode-to-mcinst-type-spec` option.
-using BitwidthSet = SmallSet<unsigned, 4>;
-struct NonTemplatedTypeSpec {
-  StringRef Type;
-  BitwidthSet Bitwidths;
-};
+  const Record *InstructionSet = Target.getInstructionSet();
+  std::vector<StringRef> InsnCPPTypes =
+      InstructionSet->getValueAsListOfStrings("InsnCPPTypes");
 
-static SmallVector<NonTemplatedTypeSpec>
-parseNonTemplatedTypeSpec(BitwidthSet &InstrBitwidths) {
-  SmallVector<NonTemplatedTypeSpec> Parsed;
-  if (DecodeToMCInstTypeSpecs.empty()) {
-    // If no `non-templated-decode-to-mcinst-type-spec` option is specified,
+  if (InsnCPPTypes.empty()) {
+    // If no `InsnCPPTypes` is specified in the instruction info,
     // create a type-spec with empty values, which will trigger generation of
     // a templated `decodeToMCInst`.
     Parsed.emplace_back();
     return Parsed;
   }
 
-  Parsed.reserve(DecodeToMCInstTypeSpecs.size());
+  // Use field locations for error reporting.
+  SMLoc CPPTypesLoc = InstructionSet->getFieldLoc("InsnCPPTypes");
+  SMLoc BitwidthsLoc = InstructionSet->getFieldLoc("InsnBitwidths");
+
+  const ListInit *InsnBitwidths =
+      InstructionSet->getValueAsListInit("InsnBitwidths");
+
+  Parsed.reserve(InsnCPPTypes.size());
   BitwidthSet OptionBitwidths;
 
-  for (StringRef TypeSpec : DecodeToMCInstTypeSpecs) {
+  for (const auto &[CPPType, BWL] :
+       zip_equal(InsnCPPTypes, InsnBitwidths->getElements())) {
     BitwidthSet Bitwidths;
-    // Each `non-templated-decode-to-mcinst-type-spec` is of the form
-    // <type>:=<list of bitwidths>. Note, <type> can in general be a templated
-    // type, so using the token ":=" as a separator to allow many general C++
-    // types here.
-    auto [Type, ListOfBitWidths] = TypeSpec.split(":=");
-    if (Type.empty())
-      PrintFatalError("Invalid typespec: " + TypeSpec);
-
-    for (StringRef BwStr : split(ListOfBitWidths, ',')) {
-      unsigned Bitwidth;
-      if (BwStr.getAsInteger(10, Bitwidth))
-        PrintFatalError("Invalid bitwidth: " + BwStr + " in typespec " +
-                        TypeSpec);
-
+    if (CPPType.empty())
+      PrintFatalError(CPPTypesLoc,
+                      "CPP Type cannot be empty in `InsnCPPTypes`");
+    const auto *BitwidthList = dyn_cast<ListInit>(BWL);
+    if (!BitwidthList || BitwidthList->empty())
+      PrintFatalError(BitwidthsLoc,
+                      "No bitwidths specified for InsnCPPType : " + CPPType);
+
+    for (int64_t Bitwidth : BitwidthList->getAsListOfInts()) {
       if (!OptionBitwidths.insert(Bitwidth).second)
-        PrintFatalError("Bitwidth " + Twine(Bitwidth) + " already specified.");
+        PrintFatalError(BitwidthsLoc,
+                        "Bitwidth " + Twine(Bitwidth) + " already specified.");
 
       if (!InstrBitwidths.contains(Bitwidth))
-        PrintFatalError(Twine("No instruction of Bitwidth ") + Twine(Bitwidth) +
-                        " supported.");
-
+        PrintFatalError(BitwidthsLoc, "No instruction of bitwidth " +
+                                          Twine(Bitwidth) + " supported.");
       InstrBitwidths.erase(Bitwidth);
       Bitwidths.insert(Bitwidth);
     }
-
-    if (Bitwidths.empty())
-      PrintFatalError("No bitwidth specified in typespec " + TypeSpec);
-
-    Parsed.emplace_back(NonTemplatedTypeSpec{Type, Bitwidths});
+    Parsed.emplace_back(NonTemplatedInsnType{CPPType, Bitwidths});
   }
 
   if (!InstrBitwidths.empty()) {
+    // FIXME: Add PrintFatalError that accepts a location and a function_ref.
     PrintFatalError([&InstrBitwidths](raw_ostream &OS) {
       OS << "Bitwidth(s) ";
-      llvm::interleaveComma(InstrBitwidths, OS);
-      OS << " missing in `non-templated-decode-to-mcinst-type-spec` options.";
+      interleaveComma(InstrBitwidths, OS);
+      OS << " missing in `InsnBitwidths`";
     });
   }
   return Parsed;
@@ -2744,12 +2735,12 @@ namespace {
     const unsigned Bitwidth = 8 * NSAndByteSize.second;
     InstrBitwidths.insert(Bitwidth);
   }
-  SmallVector<NonTemplatedTypeSpec> NonTemplatedTypeSpecs =
-      parseNonTemplatedTypeSpec(InstrBitwidths);
+  SmallVector<NonTemplatedInsnType> NonTemplatedInsnTypes =
+      parseNonTemplatedInsnTypes(InstrBitwidths);
 
   DecoderTableInfo TableInfo;
   unsigned OpcodeMask = 0;
-  for (const auto &[NTType, NTBitwidths] : NonTemplatedTypeSpecs) {
+  for (const auto &[NTType, NTBitwidths] : NonTemplatedInsnTypes) {
     // Reset the Decoders for each non-templated type.
     TableInfo.Decoders.clear();
 

>From 9b7750bfa16509cfee0e205af54ab5a94ed4a613 Mon Sep 17 00:00:00 2001
From: Rahul Joshi <rjoshi at nvidia.com>
Date: Wed, 2 Jul 2025 14:31:28 -0700
Subject: [PATCH 3/7] Specialize decodeInstruction

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

diff --git a/llvm/utils/TableGen/DecoderEmitter.cpp b/llvm/utils/TableGen/DecoderEmitter.cpp
index a8cf90a162903..dabccd1dd219e 100644
--- a/llvm/utils/TableGen/DecoderEmitter.cpp
+++ b/llvm/utils/TableGen/DecoderEmitter.cpp
@@ -2258,7 +2258,8 @@ insertBits(IntType &field, IntType bits, unsigned startBit, unsigned numBits) {
 // emitDecodeInstruction - Emit the templated helper function
 // decodeInstruction().
 static void emitDecodeInstruction(formatted_raw_ostream &OS, bool IsVarLenInst,
-                                  unsigned OpcodeMask) {
+                                  unsigned OpcodeMask,
+                                  StringRef SpecializedInsnType) {
   const bool HasTryDecode = OpcodeMask & ((1 << MCD::OPC_TryDecode) |
                                           (1 << MCD::OPC_TryDecodeOrFail));
   const bool HasCheckPredicate =
@@ -2266,6 +2267,14 @@ static void emitDecodeInstruction(formatted_raw_ostream &OS, bool IsVarLenInst,
       ((1 << MCD::OPC_CheckPredicate) | (1 << MCD::OPC_CheckPredicateOrFail));
   const bool HasSoftFail = OpcodeMask & (1 << MCD::OPC_SoftFail);
 
+  auto emitTemplate = [&OS, SpecializedInsnType] {
+    if (SpecializedInsnType.empty())
+      OS << "template <typename InsnType>\n";
+  };
+
+  StringRef InsnType =
+      SpecializedInsnType.empty() ? "InsnType" : SpecializedInsnType;
+
   OS << R"(
 static unsigned decodeNumToSkip(const uint8_t *&Ptr) {
   unsigned NumToSkip = *Ptr++;
@@ -2274,11 +2283,13 @@ static unsigned decodeNumToSkip(const uint8_t *&Ptr) {
   if (getNumToSkipInBytes() == 3)
     OS << "  NumToSkip |= (*Ptr++) << 16;\n";
   OS << R"(  return NumToSkip;
-}
+})";
 
-template <typename InsnType>
-static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], MCInst &MI,
-                                      InsnType insn, uint64_t Address,
+  emitTemplate();
+  OS << R"(
+static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], MCInst &MI, )";
+  OS << InsnType << " insn,\n";
+  OS << R"(                             uint64_t Address,
                                       const MCDisassembler *DisAsm,
                                       const MCSubtargetInfo &STI)";
   if (IsVarLenInst) {
@@ -2799,7 +2810,11 @@ namespace {
     emitPredicateFunction(OS, TableInfo.Predicates, indent(0));
 
   // Emit the main entry point for the decoder, decodeInstruction().
-  emitDecodeInstruction(OS, IsVarLenInst, OpcodeMask);
+  // Generate non-templated code if exactly one InsnCPPType was specified.
+  StringRef SpecializedInsnType =
+      NonTemplatedInsnTypes.size() == 1 ? NonTemplatedInsnTypes[0].CPPType : "";
+
+  emitDecodeInstruction(OS, IsVarLenInst, OpcodeMask, SpecializedInsnType);
 
   OS << "\n} // namespace\n";
 }

>From 22b2b0c3933cba5a9d35e4e797c31d400c1270fd Mon Sep 17 00:00:00 2001
From: Rahul Joshi <rjoshi at nvidia.com>
Date: Thu, 3 Jul 2025 17:00:22 -0700
Subject: [PATCH 4/7] Full specialization

---
 llvm/include/llvm/Target/Target.td            |  37 +--
 llvm/lib/Target/AArch64/AArch64.td            |   6 +-
 llvm/lib/Target/AMDGPU/AMDGPU.td              |   7 +
 .../Disassembler/AMDGPUDisassembler.cpp       |   2 +-
 .../M68k/Disassembler/M68kDisassembler.cpp    |   4 +-
 llvm/lib/Target/RISCV/RISCV.td                |   4 -
 llvm/test/TableGen/DecoderEmitterFnTable.td   |  10 +-
 llvm/test/TableGen/VarLenDecoder.td           |  12 +-
 llvm/test/TableGen/trydecode-emission.td      |  20 +-
 llvm/utils/TableGen/DecoderEmitter.cpp        | 264 +++++++++++-------
 10 files changed, 217 insertions(+), 149 deletions(-)

diff --git a/llvm/include/llvm/Target/Target.td b/llvm/include/llvm/Target/Target.td
index bef483d301235..9ef7bf479ef7d 100644
--- a/llvm/include/llvm/Target/Target.td
+++ b/llvm/include/llvm/Target/Target.td
@@ -1137,6 +1137,15 @@ class OptionalDefOperand<ValueType ty, dag OpTypes, dag defaultops>
   let MIOperandInfo = OpTypes;
 }
 
+// InstrDecoderOption - This class is used to provide some options to the
+// TableGen DecoderEmitter backend.
+class InstrDecoderOption<string ty, list<int> bws> {
+  string CPPType = ty;       // C++ type for generating non-templated code.
+  list<int> Bitwidths = bws; // List of bitwidths supported by the above type.
+
+  assert !not(!empty(CPPType)), "CPP type cannot be empty";
+  assert !not(!empty(Bitwidths)), "Bitwidths cannot be empty";
+}
 
 // InstrInfo - This class should only be instantiated once to provide parameters
 // which are global to the target machine.
@@ -1159,24 +1168,16 @@ class InstrInfo {
   // This option is a temporary migration help. It will go away.
   bit guessInstructionProperties = true;
 
-  // These properties, when set, opt into the non-templated variants of
-  // `decodeToMCInst` generated by TableGen DecoderEmitter backend. Using this
-  // option helps reduce the code size of the generated code as compared to the
-  // templated `decodeToMCInst` that is generated by default.
-  // For each index `I`, InsnCPPTypes[I] is a C++ type that will be used to
-  // generate a non-templated `decodeToMCInst`, and InstBitwidths[I] is a list
-  // instruction bitwidth(s) whose decoders will be included in the generated
-  // code.
-  list<string> InsnCPPTypes = [];
-  list<list<int>> InsnBitwidths = [];
-  assert !eq(!size(InsnCPPTypes), !size(InsnBitwidths)),
-     "The InsnCPPTypes and InsnBitwidths lists must be the same length";
-
-  // Make sure the InstCPPTypes, if not empty, does not contain empty strings.
-  assert !or(!empty(InsnCPPTypes), !empty(!filter(e, InsnCPPTypes, !empty(e)))),
-     "Entries in InstCPPTypes cannot be empty";
-
-  // Make sure that InsnBitwidths, if not empty, does not contain empty list.
+  // This is a list of instruction decoder options for this target. When non
+  // empty, it should list all the C++ types and associated bitwidths that this
+  // target intends to use to call the TableGen generated `decodeInstruction`
+  // function. If this list is empty, the decoder emitter will generate
+  // templated code. However, if a target intends to call this function with
+  // more than one `InsnType`, it may be beneficial to provide these decoder
+  // options to generate non-templated form of `decodeInstruction` and
+  // associated helper functions and avoid some code duplication in the
+  // `decodeToMCInst` function.
+  list<InstrDecoderOption> DecoderOptions = [];
 }
 
 // Standard Pseudo Instructions.
diff --git a/llvm/lib/Target/AArch64/AArch64.td b/llvm/lib/Target/AArch64/AArch64.td
index 3e8cabf3cb9ca..86f95488e6bb7 100644
--- a/llvm/lib/Target/AArch64/AArch64.td
+++ b/llvm/lib/Target/AArch64/AArch64.td
@@ -40,11 +40,7 @@ include "AArch64SchedPredExynos.td"
 include "AArch64SchedPredNeoverse.td"
 include "AArch64Combine.td"
 
-def AArch64InstrInfo : InstrInfo {
-  // Opt-in into non-templated code for instruction decoder.
-  let InsnCPPTypes = ["uint32_t"];
-  let InsnBitwidths = [[32]];
-}
+def AArch64InstrInfo : InstrInfo;
 
 //===----------------------------------------------------------------------===//
 // Named operands for MRS/MSR/TLBI/...
diff --git a/llvm/lib/Target/AMDGPU/AMDGPU.td b/llvm/lib/Target/AMDGPU/AMDGPU.td
index 91ace4d2b7f16..370efeb30a14d 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPU.td
+++ b/llvm/lib/Target/AMDGPU/AMDGPU.td
@@ -1994,6 +1994,13 @@ def FeatureISAVersion12_Generic: FeatureSet<
 
 def AMDGPUInstrInfo : InstrInfo {
   let guessInstructionProperties = 1;
+
+  // Opt-in into non-templated code for instruction decoder.
+  let DecoderOptions = [
+    InstrDecoderOption<"uint32_t", [32]>,
+    InstrDecoderOption<"uint64_t", [64]>,
+    InstrDecoderOption<"DecoderUInt128", [96, 128]>,
+  ];
 }
 
 def AMDGPUAsmParser : AsmParser {
diff --git a/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.cpp b/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.cpp
index 7b1ea11d58168..21fd34ea25537 100644
--- a/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.cpp
+++ b/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.cpp
@@ -591,7 +591,7 @@ DecodeStatus AMDGPUDisassembler::getInstruction(MCInst &MI, uint64_t &Size,
 
     // Try to decode DPP and SDWA first to solve conflict with VOP1 and VOP2
     // encodings
-    if (isGFX11Plus() && Bytes.size() >= 12 ) {
+    if (isGFX11Plus() && Bytes.size() >= 12) {
       DecoderUInt128 DecW = eat12Bytes(Bytes);
 
       if (isGFX11() &&
diff --git a/llvm/lib/Target/M68k/Disassembler/M68kDisassembler.cpp b/llvm/lib/Target/M68k/Disassembler/M68kDisassembler.cpp
index 4ec18fe6bf544..ee453cfc0924e 100644
--- a/llvm/lib/Target/M68k/Disassembler/M68kDisassembler.cpp
+++ b/llvm/lib/Target/M68k/Disassembler/M68kDisassembler.cpp
@@ -111,13 +111,13 @@ static DecodeStatus DecodeFPCSCRegisterClass(MCInst &Inst, uint64_t RegNo,
 }
 #define DecodeFPICRegisterClass DecodeFPCSCRegisterClass
 
-static DecodeStatus DecodeCCRCRegisterClass(MCInst &Inst, APInt &Insn,
+static DecodeStatus DecodeCCRCRegisterClass(MCInst &Inst, const APInt &Insn,
                                             uint64_t Address,
                                             const void *Decoder) {
   llvm_unreachable("unimplemented");
 }
 
-static DecodeStatus DecodeSRCRegisterClass(MCInst &Inst, APInt &Insn,
+static DecodeStatus DecodeSRCRegisterClass(MCInst &Inst, const APInt &Insn,
                                            uint64_t Address,
                                            const void *Decoder) {
   llvm_unreachable("unimplemented");
diff --git a/llvm/lib/Target/RISCV/RISCV.td b/llvm/lib/Target/RISCV/RISCV.td
index b3ce392d27a17..b24d8637cb27f 100644
--- a/llvm/lib/Target/RISCV/RISCV.td
+++ b/llvm/lib/Target/RISCV/RISCV.td
@@ -85,10 +85,6 @@ include "RISCVPfmCounters.td"
 
 def RISCVInstrInfo : InstrInfo {
   let guessInstructionProperties = 0;
-
-  // Opt-in into non-templated code for instruction decoder.
-  let InsnCPPTypes = ["uint64_t"];
-  let InsnBitwidths = [[16, 32, 48]];
 }
 
 def RISCVAsmParser : AsmParser {
diff --git a/llvm/test/TableGen/DecoderEmitterFnTable.td b/llvm/test/TableGen/DecoderEmitterFnTable.td
index 7bed18c19a513..837ec3bdc5c84 100644
--- a/llvm/test/TableGen/DecoderEmitterFnTable.td
+++ b/llvm/test/TableGen/DecoderEmitterFnTable.td
@@ -71,11 +71,11 @@ def Inst3 : TestInstruction {
   let AsmString = "Inst3";
 }
 
-// CHECK-LABEL: DecodeStatus decodeFn0(DecodeStatus S, InsnType insn, MCInst &MI, uint64_t Address, const MCDisassembler *Decoder, bool &DecodeComplete)
-// CHECK-LABEL: DecodeStatus decodeFn1(DecodeStatus S, InsnType insn, MCInst &MI, uint64_t Address, const MCDisassembler *Decoder, bool &DecodeComplete)
-// CHECK-LABEL: DecodeStatus decodeFn2(DecodeStatus S, InsnType insn, MCInst &MI, uint64_t Address, const MCDisassembler *Decoder, bool &DecodeComplete)
-// CHECK-LABEL: DecodeStatus decodeFn3(DecodeStatus S, InsnType insn, MCInst &MI, uint64_t Address, const MCDisassembler *Decoder, bool &DecodeComplete)
-// CHECK-LABEL: decodeToMCInst(unsigned Idx, DecodeStatus S, InsnType insn, MCInst &MI, uint64_t Address, const MCDisassembler *Decoder, bool &DecodeComplete)
+// CHECK-LABEL: DecodeStatus decodeFn0(DecodeStatus S, const InsnType &insn, MCInst &MI, uint64_t Address, const MCDisassembler *Decoder, bool &DecodeComplete)
+// CHECK-LABEL: DecodeStatus decodeFn1(DecodeStatus S, const InsnType &insn, MCInst &MI, uint64_t Address, const MCDisassembler *Decoder, bool &DecodeComplete)
+// CHECK-LABEL: DecodeStatus decodeFn2(DecodeStatus S, const InsnType &insn, MCInst &MI, uint64_t Address, const MCDisassembler *Decoder, bool &DecodeComplete)
+// CHECK-LABEL: DecodeStatus decodeFn3(DecodeStatus S, const InsnType &insn, MCInst &MI, uint64_t Address, const MCDisassembler *Decoder, bool &DecodeComplete)
+// CHECK-LABEL: decodeToMCInst(unsigned Idx, DecodeStatus S, const InsnType &insn, MCInst &MI, uint64_t Address, const MCDisassembler *Decoder, bool &DecodeComplete)
 // CHECK: static constexpr DecodeFnTy decodeFnTable[]
 // CHECK-NEXT: decodeFn0,
 // CHECK-NEXT: decodeFn1,
diff --git a/llvm/test/TableGen/VarLenDecoder.td b/llvm/test/TableGen/VarLenDecoder.td
index 2359bd2c15145..d438e64264cbd 100644
--- a/llvm/test/TableGen/VarLenDecoder.td
+++ b/llvm/test/TableGen/VarLenDecoder.td
@@ -47,6 +47,12 @@ def FOO32 : MyVarInst<MemOp32> {
   );
 }
 
+// Instruction length table
+// CHECK-LABEL: InstrLenTable
+// CHECK: 27,
+// CHECK-NEXT: 43,
+// CHECK-NEXT: };
+
 // CHECK-SMALL:      /* 0 */       MCD::OPC_ExtractField, 3, 5,  // Inst{7-3} ...
 // CHECK-SMALL-NEXT: /* 3 */       MCD::OPC_FilterValue, 8, 4, 0, // Skip to: 11
 // CHECK-SMALL-NEXT: /* 7 */       MCD::OPC_Decode, {{[0-9]+}}, {{[0-9]+}}, 0, // Opcode: FOO16
@@ -81,12 +87,6 @@ def FOO32 : MyVarInst<MemOp32> {
 // CHECK-NEXT: MI.addOperand(MCOperand::createImm(tmp));
 // CHECK-NEXT: return S;
 
-// Instruction length table
-// CHECK-LABEL: InstrLenTable
-// CHECK: 27,
-// CHECK-NEXT: 43,
-// CHECK-NEXT: };
-
 // CHECK-LABEL: decodeInstruction
 // CHECK-LABEL: case MCD::OPC_ExtractField: {
 // CHECK: makeUp(insn, Start + Len);
diff --git a/llvm/test/TableGen/trydecode-emission.td b/llvm/test/TableGen/trydecode-emission.td
index c3178dd71cf4b..8e427c8a7107b 100644
--- a/llvm/test/TableGen/trydecode-emission.td
+++ b/llvm/test/TableGen/trydecode-emission.td
@@ -34,6 +34,17 @@ def InstB : TestInstruction {
   let hasCompleteDecoder = 0;
 }
 
+// CHECK-LABEL: decodeNumToSkip
+// CHECK-NEXT:  unsigned NumToSkip = *Ptr++;
+// CHECK-NEXT:  NumToSkip |= (*Ptr++) << 8;
+// CHECK-NEXT:  return NumToSkip;
+
+// CHECK-LARGE-LABEL: decodeNumToSkip
+// CHECK-LARGE-NEXT:  unsigned NumToSkip = *Ptr++;
+// CHECK-LARGE-NEXT:  NumToSkip |= (*Ptr++) << 8;
+// CHECK-LARGE-NEXT:  NumToSkip |= (*Ptr++) << 16;
+// CHECK-LARGE-NEXT:  return NumToSkip;
+
 // CHECK:      /* 0 */       MCD::OPC_ExtractField, 4, 4,  // Inst{7-4} ...
 // CHECK-NEXT: /* 3 */       MCD::OPC_FilterValueOrFail, 0,
 // CHECK-NEXT: /* 5 */       MCD::OPC_CheckField, 2, 2, 0, 6, 0, // Skip to: 17
@@ -43,10 +54,6 @@ def InstB : TestInstruction {
 
 // CHECK: if (!Check(S, DecodeInstB(MI, insn, Address, Decoder))) { DecodeComplete = false; return MCDisassembler::Fail; }
 
-// CHECK:       unsigned NumToSkip = *Ptr++;
-// CHECK-NEXT:  NumToSkip |= (*Ptr++) << 8;
-// CHECK-NEXT:  return NumToSkip;
-
 // CHECK-LARGE:      /* 0 */       MCD::OPC_ExtractField, 4, 4,  // Inst{7-4} ...
 // CHECK-LARGE-NEXT: /* 3 */       MCD::OPC_FilterValueOrFail, 0,
 // CHECK-LARGE-NEXT: /* 5 */       MCD::OPC_CheckField, 2, 2, 0, 7, 0, 0, // Skip to: 19
@@ -55,8 +62,3 @@ def InstB : TestInstruction {
 // CHECK-LARGE-NEXT: /* 23 */      MCD::OPC_Fail,
 
 // CHECK-LARGE: if (!Check(S, DecodeInstB(MI, insn, Address, Decoder))) { DecodeComplete = false; return MCDisassembler::Fail; }
-
-// CHECK-LARGE:       unsigned NumToSkip = *Ptr++;
-// CHECK-LARGE-NEXT:  NumToSkip |= (*Ptr++) << 8;
-// CHECK-LARGE-NEXT:  NumToSkip |= (*Ptr++) << 16;
-// CHECK-LARGE-NEXT:  return NumToSkip;
diff --git a/llvm/utils/TableGen/DecoderEmitter.cpp b/llvm/utils/TableGen/DecoderEmitter.cpp
index dabccd1dd219e..ba4bab9793eb1 100644
--- a/llvm/utils/TableGen/DecoderEmitter.cpp
+++ b/llvm/utils/TableGen/DecoderEmitter.cpp
@@ -223,6 +223,9 @@ using BitwidthSet = SmallSet<unsigned, 4>;
 struct NonTemplatedInsnType {
   StringRef CPPType;
   BitwidthSet Bitwidths;
+
+  NonTemplatedInsnType(StringRef CPPType, BitwidthSet Bitwidths)
+      : CPPType(CPPType), Bitwidths(std::move(Bitwidths)) {}
 };
 
 class DecoderEmitter {
@@ -1077,21 +1080,25 @@ void DecoderEmitter::emitPredicateFunction(formatted_raw_ostream &OS,
   OS << Indent << "}\n\n";
 }
 
+static void emitTemplate(formatted_raw_ostream &OS,
+                         StringRef SpecializedInsnType) {
+  if (SpecializedInsnType.empty())
+    OS << "template <typename InsnType>\n";
+}
+
+static StringRef getInsnType(StringRef SpecializedInsnType) {
+  return SpecializedInsnType.empty() ? "InsnType" : SpecializedInsnType;
+}
+
 void DecoderEmitter::emitDecoderFunction(formatted_raw_ostream &OS,
                                          DecoderSet &Decoders,
                                          StringRef SpecializedInsnType,
                                          indent Indent) const {
-  auto emitTemplate = [&OS, SpecializedInsnType, &Indent] {
-    if (SpecializedInsnType.empty())
-      OS << Indent << "template <typename InsnType>\n";
-  };
-
-  StringRef InsnType =
-      SpecializedInsnType.empty() ? "InsnType" : SpecializedInsnType;
-
   // The decoder function is just a big switch statement or a table of function
   // pointers based on the input decoder index.
 
+  StringRef InsnType = getInsnType(SpecializedInsnType);
+
   // TODO: When InsnType is large, using uint64_t limits all fields to 64 bits
   // It would be better for emitBinaryParser to use a 64-bit tmp whenever
   // possible but fall back to an InsnType-sized tmp for truly large fields.
@@ -1100,14 +1107,14 @@ void DecoderEmitter::emitDecoderFunction(formatted_raw_ostream &OS,
       "uint64_t>;\n",
       InsnType);
   auto DecodeParams =
-      formatv("DecodeStatus S, {} insn, MCInst &MI, uint64_t Address, const "
-              "MCDisassembler *Decoder, bool &DecodeComplete",
+      formatv("DecodeStatus S, const {} &insn, MCInst &MI, uint64_t Address, "
+              "const MCDisassembler *Decoder, bool &DecodeComplete",
               InsnType);
 
   if (UseFnTableInDecodeToMCInst) {
     // Emit a function for each case first.
     for (const auto &[Index, Decoder] : enumerate(Decoders)) {
-      emitTemplate();
+      emitTemplate(OS, SpecializedInsnType);
       OS << Indent << "DecodeStatus decodeFn" << Index << "(" << DecodeParams
          << ") {\n";
       Indent += 2;
@@ -1121,7 +1128,7 @@ void DecoderEmitter::emitDecoderFunction(formatted_raw_ostream &OS,
   }
 
   OS << Indent << "// Handling " << Decoders.size() << " cases.\n";
-  emitTemplate();
+  emitTemplate(OS, SpecializedInsnType);
   OS << Indent << "static DecodeStatus decodeToMCInst(unsigned Idx, "
      << DecodeParams << ") {\n";
   Indent += 2;
@@ -2196,12 +2203,19 @@ populateInstruction(const CodeGenTarget &Target, const Record &EncodingDef,
   return Bits.getNumBits();
 }
 
+static bool isKnownIntegralType(StringRef InsnType) {
+  static constexpr StringLiteral KnownIntegralTypes[] = {"uint16_t", "uint32_t",
+                                                         "uint64_t"};
+  return llvm::is_contained(KnownIntegralTypes, InsnType);
+}
+
 // emitFieldFromInstruction - Emit the templated helper function
 // fieldFromInstruction().
 // On Windows we make sure that this function is not inlined when
 // using the VS compiler. It has a bug which causes the function
 // to be optimized out in some circumstances. See llvm.org/pr38292
-static void emitFieldFromInstruction(formatted_raw_ostream &OS) {
+static void emitFieldFromInstruction(formatted_raw_ostream &OS,
+                                     StringRef SpecializedInsnType) {
   OS << R"(
 // Helper functions for extracting fields from encoded instructions.
 // InsnType must either be integral or an APInt-like object that must:
@@ -2209,35 +2223,83 @@ static void emitFieldFromInstruction(formatted_raw_ostream &OS) {
 // * Support extractBitsAsZExtValue(numBits, startBit)
 // * Support the ~, &, ==, and != operators with other objects of the same type
 // * Support the != and bitwise & with uint64_t
-template <typename InsnType>
+
+// Helper macro to disable inlining of `fieldFromInstruction`.
 #if defined(_MSC_VER) && !defined(__clang__)
-__declspec(noinline)
+#define DEC_EMIT_NO_INLINE __declspec(noinline)
+#else
+#define DEC_EMIT_NO_INLINE
 #endif
-static std::enable_if_t<std::is_integral<InsnType>::value, InsnType>
-fieldFromInstruction(const InsnType &insn, unsigned startBit,
-                     unsigned numBits) {
+
+)";
+  StringRef InsnType = getInsnType(SpecializedInsnType);
+
+  // If InsnType is not a template type argument, we cannot use std::enable_if_t
+  // to enable or disable one of the versions of `fieldFromInstruction`. Use a
+  // set if pre-defined strings to detect which version of
+  // `fieldFromInstruction` to emit.
+  bool IsIntegralType = isKnownIntegralType(InsnType);
+  bool GenerateTemplatedForm = SpecializedInsnType.empty();
+
+  if (GenerateTemplatedForm || IsIntegralType) {
+    if (GenerateTemplatedForm) {
+      emitTemplate(OS, SpecializedInsnType);
+      OS << formatv("DEC_EMIT_NO_INLINE static "
+                    "std::enable_if_t<std::is_integral<{0}>::value, {0}>\n",
+                    InsnType);
+    } else {
+      OS << formatv("DEC_EMIT_NO_INLINE static {} ", InsnType);
+    }
+
+    OS << formatv(
+        R"(fieldFromInstruction(const {0} &insn, unsigned startBit, unsigned numBits) {{
   assert(startBit + numBits <= 64 && "Cannot support >64-bit extractions!");
-  assert(startBit + numBits <= (sizeof(InsnType) * 8) &&
+  assert(startBit + numBits <= (sizeof({0}) * 8) &&
          "Instruction field out of bounds!");
-  InsnType fieldMask;
-  if (numBits == sizeof(InsnType) * 8)
-    fieldMask = (InsnType)(-1LL);
+  {0} fieldMask;
+  if (numBits == sizeof({0}) * 8)
+    fieldMask = ({0})(-1LL);
   else
-    fieldMask = (((InsnType)1 << numBits) - 1) << startBit;
+    fieldMask = ((({0})1 << numBits) - 1) << startBit;
   return (insn & fieldMask) >> startBit;
 }
 
-template <typename InsnType>
-static std::enable_if_t<!std::is_integral<InsnType>::value, uint64_t>
-fieldFromInstruction(const InsnType &insn, unsigned startBit,
-                     unsigned numBits) {
+)",
+        InsnType);
+  } // if (GenerateTemplatedForm || IsIntegralType) {
+
+  if (GenerateTemplatedForm || !IsIntegralType) {
+    if (GenerateTemplatedForm) {
+      emitTemplate(OS, SpecializedInsnType);
+      OS << formatv(
+          "static std::enable_if_t<!std::is_integral<{0}>::value, uint64_t>\n",
+          InsnType);
+    } else {
+      OS << formatv("static uint64_t ");
+    }
+
+    OS << formatv(R"(fieldFromInstruction(const {0} &insn, unsigned startBit,
+                     unsigned numBits) {{
   return insn.extractBitsAsZExtValue(numBits, startBit);
 }
-)";
+)",
+                  InsnType);
+  } // if (GenerateTemplatedForm || !IsIntegralType)
+  OS << "#undef DEC_EMIT_NO_INLINE\n";
 }
 
 // emitInsertBits - Emit the templated helper function insertBits().
-static void emitInsertBits(formatted_raw_ostream &OS) {
+static void emitInsertBits(formatted_raw_ostream &OS,
+                           StringRef SpecializedInsnType) {
+  bool GenerateTemplatedForm = SpecializedInsnType.empty();
+  StringRef InsnType = getInsnType(SpecializedInsnType);
+  bool IsIntegralType = isKnownIntegralType(InsnType);
+
+  auto FuncDecl = formatv(R"([[maybe_unused]]
+static void insertBits({0} &field, {0} bits, unsigned startBit,
+                       unsigned numBits) {{)",
+                          InsnType);
+
   OS << R"(
 // Helper function for inserting bits extracted from an encoded instruction into
 // an integer-typed field.
@@ -2252,11 +2314,10 @@ insertBits(IntType &field, IntType bits, unsigned startBit, unsigned numBits) {
   (void)numBits;
   field |= bits << startBit;
 }
-)";
+)",
 }
 
-// emitDecodeInstruction - Emit the templated helper function
-// decodeInstruction().
+// emitDecodeInstruction - Emit the entry function function decodeInstruction().
 static void emitDecodeInstruction(formatted_raw_ostream &OS, bool IsVarLenInst,
                                   unsigned OpcodeMask,
                                   StringRef SpecializedInsnType) {
@@ -2267,29 +2328,19 @@ static void emitDecodeInstruction(formatted_raw_ostream &OS, bool IsVarLenInst,
       ((1 << MCD::OPC_CheckPredicate) | (1 << MCD::OPC_CheckPredicateOrFail));
   const bool HasSoftFail = OpcodeMask & (1 << MCD::OPC_SoftFail);
 
-  auto emitTemplate = [&OS, SpecializedInsnType] {
-    if (SpecializedInsnType.empty())
-      OS << "template <typename InsnType>\n";
-  };
-
-  StringRef InsnType =
-      SpecializedInsnType.empty() ? "InsnType" : SpecializedInsnType;
-
-  OS << R"(
-static unsigned decodeNumToSkip(const uint8_t *&Ptr) {
-  unsigned NumToSkip = *Ptr++;
-  NumToSkip |= (*Ptr++) << 8;
-)";
-  if (getNumToSkipInBytes() == 3)
-    OS << "  NumToSkip |= (*Ptr++) << 16;\n";
-  OS << R"(  return NumToSkip;
-})";
+  StringRef InsnType = getInsnType(SpecializedInsnType);
 
-  emitTemplate();
+  emitTemplate(OS, SpecializedInsnType);
   OS << R"(
 static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], MCInst &MI, )";
-  OS << InsnType << " insn,\n";
-  OS << R"(                             uint64_t Address,
+  // For variable length instructions, use a non-const reference to match the
+  // signature of the `makeUp` function passed in.
+  if (IsVarLenInst)
+    OS << InsnType << " &insn,";
+  else
+    OS << "const " << InsnType << " &insn,";
+  OS << R"(
+                                      uint64_t Address,
                                       const MCDisassembler *DisAsm,
                                       const MCSubtargetInfo &STI)";
   if (IsVarLenInst) {
@@ -2493,16 +2544,31 @@ static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], MCInst &MI, )
 )";
 }
 
+static void emitCommonFunctions(formatted_raw_ostream &OS) {
+  OS << R"(
 // Helper to propagate SoftFail status. Returns false if the status is Fail;
 // callers are expected to early-exit in that condition. (Note, the '&' operator
 // is correct to propagate the values of this enum; see comment on 'enum
 // DecodeStatus'.)
-static void emitCheck(formatted_raw_ostream &OS) {
-  OS << R"(
 static bool Check(DecodeStatus &Out, DecodeStatus In) {
   Out = static_cast<DecodeStatus>(Out & In);
   return Out != MCDisassembler::Fail;
 }
+)";
+
+  OS << R"(
+// Helper to decode the `NumToSkip` value encoded in the decoder table.
+static unsigned decodeNumToSkip(const uint8_t *&Ptr) {
+  unsigned NumToSkip = *Ptr++;
+  NumToSkip |= (*Ptr++) << 8;
+)";
+  if (getNumToSkipInBytes() == 3)
+    OS << "  NumToSkip |= (*Ptr++) << 16;\n";
+  OS << R"(  return NumToSkip;
+}
+
+// Forward declaration.
+[[maybe_unused]] static bool checkDecoderPredicate(unsigned Idx, const FeatureBitset &Bits);
 
 )";
 }
@@ -2572,39 +2638,36 @@ DecoderEmitter::parseNonTemplatedInsnTypes(BitwidthSet &InstrBitwidths) {
   SmallVector<NonTemplatedInsnType> Parsed;
 
   const Record *InstructionSet = Target.getInstructionSet();
-  std::vector<StringRef> InsnCPPTypes =
-      InstructionSet->getValueAsListOfStrings("InsnCPPTypes");
-
-  if (InsnCPPTypes.empty()) {
-    // If no `InsnCPPTypes` is specified in the instruction info,
-    // create a type-spec with empty values, which will trigger generation of
-    // a templated `decodeToMCInst`.
-    Parsed.emplace_back();
+  std::vector<const Record *> DecoderOptions =
+      InstructionSet->getValueAsListOfDefs("DecoderOptions");
+
+  if (DecoderOptions.empty()) {
+    // If no `DecoderOptions` is specified in the instruction info, create one
+    // with empty values, which will trigger generation of a template code.
+    Parsed.emplace_back(StringRef(""), BitwidthSet{});
     return Parsed;
   }
 
-  // Use field locations for error reporting.
-  SMLoc CPPTypesLoc = InstructionSet->getFieldLoc("InsnCPPTypes");
-  SMLoc BitwidthsLoc = InstructionSet->getFieldLoc("InsnBitwidths");
-
-  const ListInit *InsnBitwidths =
-      InstructionSet->getValueAsListInit("InsnBitwidths");
-
-  Parsed.reserve(InsnCPPTypes.size());
+  Parsed.reserve(DecoderOptions.size());
   BitwidthSet OptionBitwidths;
 
-  for (const auto &[CPPType, BWL] :
-       zip_equal(InsnCPPTypes, InsnBitwidths->getElements())) {
-    BitwidthSet Bitwidths;
+  for (const Record *Option : DecoderOptions) {
+    // Use field locations for error reporting.
+    SMLoc CPPTypesLoc = Option->getFieldLoc("CPPType");
+    SMLoc BitwidthsLoc = Option->getFieldLoc("Bitwidths");
+
+    StringRef CPPType = Option->getValueAsString("CPPType");
     if (CPPType.empty())
       PrintFatalError(CPPTypesLoc,
                       "CPP Type cannot be empty in `InsnCPPTypes`");
-    const auto *BitwidthList = dyn_cast<ListInit>(BWL);
-    if (!BitwidthList || BitwidthList->empty())
+
+    const ListInit *BWL = Option->getValueAsListInit("Bitwidths");
+    if (!BWL || BWL->empty())
       PrintFatalError(BitwidthsLoc,
-                      "No bitwidths specified for InsnCPPType : " + CPPType);
+                      "No bitwidths specified for CPPType : " + CPPType);
 
-    for (int64_t Bitwidth : BitwidthList->getAsListOfInts()) {
+    BitwidthSet Bitwidths;
+    for (int64_t Bitwidth : BWL->getAsListOfInts()) {
       if (!OptionBitwidths.insert(Bitwidth).second)
         PrintFatalError(BitwidthsLoc,
                         "Bitwidth " + Twine(Bitwidth) + " already specified.");
@@ -2615,7 +2678,7 @@ DecoderEmitter::parseNonTemplatedInsnTypes(BitwidthSet &InstrBitwidths) {
       InstrBitwidths.erase(Bitwidth);
       Bitwidths.insert(Bitwidth);
     }
-    Parsed.emplace_back(NonTemplatedInsnType{CPPType, Bitwidths});
+    Parsed.emplace_back(CPPType, Bitwidths);
   }
 
   if (!InstrBitwidths.empty()) {
@@ -2645,9 +2708,7 @@ void DecoderEmitter::run(raw_ostream &o) {
 namespace {
 )";
 
-  emitFieldFromInstruction(OS);
-  emitInsertBits(OS);
-  emitCheck(OS);
+  emitCommonFunctions(OS);
 
   Target.reverseBitsForLittleEndianEncoding();
 
@@ -2697,7 +2758,7 @@ namespace {
       OpcMap;
   std::map<unsigned, std::vector<OperandInfo>> Operands;
   std::vector<unsigned> InstrLen;
-  bool IsVarLenInst = Target.hasVariableLengthEncodings();
+  const bool IsVarLenInst = Target.hasVariableLengthEncodings();
   unsigned MaxInstLen = 0;
 
   for (const auto &[NEI, NumberedEncoding] : enumerate(NumberedEncodings)) {
@@ -2740,6 +2801,12 @@ namespace {
     }
   }
 
+  // For variable instruction, we emit a instruction length table
+  // to let the decoder know how long the instructions are.
+  // You can see example usage in M68k's disassembler.
+  if (IsVarLenInst)
+    emitInstrLenTable(OS, InstrLen);
+
   // Collect all allowed Bitwidths for instructions.
   BitwidthSet InstrBitwidths;
   for (const auto &[NSAndByteSize, _] : OpcMap) {
@@ -2750,10 +2817,21 @@ namespace {
       parseNonTemplatedInsnTypes(InstrBitwidths);
 
   DecoderTableInfo TableInfo;
-  unsigned OpcodeMask = 0;
+  bool HasCheckPredicate = false;
   for (const auto &[NTType, NTBitwidths] : NonTemplatedInsnTypes) {
     // Reset the Decoders for each non-templated type.
     TableInfo.Decoders.clear();
+    unsigned OpcodeMask = 0;
+
+    if (!NTType.empty()) {
+      OS << "// ------------------------------------------------------------\n";
+      OS << "// Decoder tables and functions for bitwidths: ";
+      interleaveComma(NTBitwidths, OS);
+      OS << "\n// Using InsnType = " << NTType << '\n';
+    }
+
+    emitFieldFromInstruction(OS, NTType);
+    emitInsertBits(OS, NTType);
 
     for (const auto &[NSAndByteSize, EncodingIDs] : OpcMap) {
       const std::string &DecoderNamespace = NSAndByteSize.first;
@@ -2793,29 +2871,17 @@ namespace {
 
     // Emit the decoder function for this BitWidth.
     emitDecoderFunction(OS, TableInfo.Decoders, NTType, indent(0));
-  }
 
-  // For variable instruction, we emit a instruction length table
-  // to let the decoder know how long the instructions are.
-  // You can see example usage in M68k's disassembler.
-  if (IsVarLenInst)
-    emitInstrLenTable(OS, InstrLen);
+    HasCheckPredicate |= OpcodeMask & ((1 << MCD::OPC_CheckPredicate) |
+                                       (1 << MCD::OPC_CheckPredicateOrFail));
 
-  const bool HasCheckPredicate =
-      OpcodeMask &
-      ((1 << MCD::OPC_CheckPredicate) | (1 << MCD::OPC_CheckPredicateOrFail));
+    emitDecodeInstruction(OS, IsVarLenInst, OpcodeMask, NTType);
+  }
 
   // Emit the predicate function.
   if (HasCheckPredicate)
     emitPredicateFunction(OS, TableInfo.Predicates, indent(0));
 
-  // Emit the main entry point for the decoder, decodeInstruction().
-  // Generate non-templated code if exactly one InsnCPPType was specified.
-  StringRef SpecializedInsnType =
-      NonTemplatedInsnTypes.size() == 1 ? NonTemplatedInsnTypes[0].CPPType : "";
-
-  emitDecodeInstruction(OS, IsVarLenInst, OpcodeMask, SpecializedInsnType);
-
   OS << "\n} // namespace\n";
 }
 

>From c4a56dbd396e9209d7fd308dd0b842f27824897b Mon Sep 17 00:00:00 2001
From: Rahul Joshi <rjoshi at nvidia.com>
Date: Thu, 3 Jul 2025 21:00:01 -0700
Subject: [PATCH 5/7] Rename NonTemplatedInsnType to a more generic
 DecoderOption

---
 llvm/include/llvm/Target/Target.td            |  25 +-
 llvm/lib/Target/AArch64/AArch64.td            |   4 +-
 llvm/lib/Target/AMDGPU/AMDGPU.td              |   8 +-
 .../Disassembler/AMDGPUDisassembler.cpp       |  27 +-
 .../AMDGPU/Disassembler/AMDGPUDisassembler.h  |  38 --
 llvm/lib/Target/ARM/ARM.td                    |   4 +-
 llvm/lib/Target/M68k/M68k.td                  |   4 +-
 llvm/test/TableGen/DecoderEmitterFnTable.td   |  16 +-
 llvm/utils/TableGen/Common/Types.cpp          |  12 +
 llvm/utils/TableGen/Common/Types.h            |   5 +
 llvm/utils/TableGen/DecoderEmitter.cpp        | 429 ++++++++----------
 .../utils/TableGen/SearchableTableEmitter.cpp |  10 +-
 12 files changed, 246 insertions(+), 336 deletions(-)

diff --git a/llvm/include/llvm/Target/Target.td b/llvm/include/llvm/Target/Target.td
index 9ef7bf479ef7d..99f802b7b7251 100644
--- a/llvm/include/llvm/Target/Target.td
+++ b/llvm/include/llvm/Target/Target.td
@@ -1137,16 +1137,6 @@ class OptionalDefOperand<ValueType ty, dag OpTypes, dag defaultops>
   let MIOperandInfo = OpTypes;
 }
 
-// InstrDecoderOption - This class is used to provide some options to the
-// TableGen DecoderEmitter backend.
-class InstrDecoderOption<string ty, list<int> bws> {
-  string CPPType = ty;       // C++ type for generating non-templated code.
-  list<int> Bitwidths = bws; // List of bitwidths supported by the above type.
-
-  assert !not(!empty(CPPType)), "CPP type cannot be empty";
-  assert !not(!empty(Bitwidths)), "Bitwidths cannot be empty";
-}
-
 // InstrInfo - This class should only be instantiated once to provide parameters
 // which are global to the target machine.
 //
@@ -1168,16 +1158,11 @@ class InstrInfo {
   // This option is a temporary migration help. It will go away.
   bit guessInstructionProperties = true;
 
-  // This is a list of instruction decoder options for this target. When non
-  // empty, it should list all the C++ types and associated bitwidths that this
-  // target intends to use to call the TableGen generated `decodeInstruction`
-  // function. If this list is empty, the decoder emitter will generate
-  // templated code. However, if a target intends to call this function with
-  // more than one `InsnType`, it may be beneficial to provide these decoder
-  // options to generate non-templated form of `decodeInstruction` and
-  // associated helper functions and avoid some code duplication in the
-  // `decodeToMCInst` function.
-  list<InstrDecoderOption> DecoderOptions = [];
+  // Option to choose bewteen templated and non-templated code from decoder
+  // emitter. This means that the generated `decodeInstruction` function will
+  // use auto-inferred types for the instruction payload instead of generating
+  // templated code using `InsnType` for the instruction payload.
+  bit GenerateTemplatedDecoder = true;
 }
 
 // Standard Pseudo Instructions.
diff --git a/llvm/lib/Target/AArch64/AArch64.td b/llvm/lib/Target/AArch64/AArch64.td
index 86f95488e6bb7..5e1de716b6f79 100644
--- a/llvm/lib/Target/AArch64/AArch64.td
+++ b/llvm/lib/Target/AArch64/AArch64.td
@@ -40,7 +40,9 @@ include "AArch64SchedPredExynos.td"
 include "AArch64SchedPredNeoverse.td"
 include "AArch64Combine.td"
 
-def AArch64InstrInfo : InstrInfo;
+def AArch64InstrInfo : InstrInfo {
+  let GenerateTemplatedDecoder = false;
+}
 
 //===----------------------------------------------------------------------===//
 // Named operands for MRS/MSR/TLBI/...
diff --git a/llvm/lib/Target/AMDGPU/AMDGPU.td b/llvm/lib/Target/AMDGPU/AMDGPU.td
index 370efeb30a14d..bedf8e92fa519 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPU.td
+++ b/llvm/lib/Target/AMDGPU/AMDGPU.td
@@ -1994,13 +1994,7 @@ def FeatureISAVersion12_Generic: FeatureSet<
 
 def AMDGPUInstrInfo : InstrInfo {
   let guessInstructionProperties = 1;
-
-  // Opt-in into non-templated code for instruction decoder.
-  let DecoderOptions = [
-    InstrDecoderOption<"uint32_t", [32]>,
-    InstrDecoderOption<"uint64_t", [64]>,
-    InstrDecoderOption<"DecoderUInt128", [96, 128]>,
-  ];
+  let GenerateTemplatedDecoder = false;
 }
 
 def AMDGPUAsmParser : AsmParser {
diff --git a/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.cpp b/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.cpp
index 21fd34ea25537..237beae5a3944 100644
--- a/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.cpp
+++ b/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.cpp
@@ -35,6 +35,7 @@
 #include "llvm/MC/TargetRegistry.h"
 #include "llvm/Support/AMDHSAKernelDescriptor.h"
 #include "llvm/Support/Compiler.h"
+#include <bitset>
 
 using namespace llvm;
 
@@ -490,26 +491,24 @@ template <typename T> static inline T eatBytes(ArrayRef<uint8_t>& Bytes) {
   return Res;
 }
 
-static inline DecoderUInt128 eat12Bytes(ArrayRef<uint8_t> &Bytes) {
+static inline std::bitset<96> eat12Bytes(ArrayRef<uint8_t> &Bytes) {
+  using namespace llvm::support::endian;
   assert(Bytes.size() >= 12);
-  uint64_t Lo =
-      support::endian::read<uint64_t, llvm::endianness::little>(Bytes.data());
+  std::bitset<96> Lo(read<uint64_t, endianness::little>(Bytes.data()));
   Bytes = Bytes.slice(8);
-  uint64_t Hi =
-      support::endian::read<uint32_t, llvm::endianness::little>(Bytes.data());
+  std::bitset<96> Hi(read<uint32_t, endianness::little>(Bytes.data()));
   Bytes = Bytes.slice(4);
-  return DecoderUInt128(Lo, Hi);
+  return (Hi << 64) | Lo;
 }
 
-static inline DecoderUInt128 eat16Bytes(ArrayRef<uint8_t> &Bytes) {
+static inline std::bitset<128> eat16Bytes(ArrayRef<uint8_t> &Bytes) {
+  using namespace llvm::support::endian;
   assert(Bytes.size() >= 16);
-  uint64_t Lo =
-      support::endian::read<uint64_t, llvm::endianness::little>(Bytes.data());
+  std::bitset<128> Lo(read<uint64_t, endianness::little>(Bytes.data()));
   Bytes = Bytes.slice(8);
-  uint64_t Hi =
-      support::endian::read<uint64_t, llvm::endianness::little>(Bytes.data());
+  std::bitset<128> Hi(read<uint64_t, endianness::little>(Bytes.data()));
   Bytes = Bytes.slice(8);
-  return DecoderUInt128(Lo, Hi);
+  return (Hi << 64) | Lo;
 }
 
 void AMDGPUDisassembler::decodeImmOperands(MCInst &MI,
@@ -592,7 +591,7 @@ DecodeStatus AMDGPUDisassembler::getInstruction(MCInst &MI, uint64_t &Size,
     // Try to decode DPP and SDWA first to solve conflict with VOP1 and VOP2
     // encodings
     if (isGFX11Plus() && Bytes.size() >= 12) {
-      DecoderUInt128 DecW = eat12Bytes(Bytes);
+      std::bitset<96> DecW = eat12Bytes(Bytes);
 
       if (isGFX11() &&
           tryDecodeInst(DecoderTableGFX1196, DecoderTableGFX11_FAKE1696, MI,
@@ -618,7 +617,7 @@ DecodeStatus AMDGPUDisassembler::getInstruction(MCInst &MI, uint64_t &Size,
 
     } else if (Bytes.size() >= 16 &&
                STI.hasFeature(AMDGPU::FeatureGFX950Insts)) {
-      DecoderUInt128 DecW = eat16Bytes(Bytes);
+      std::bitset<128> DecW = eat16Bytes(Bytes);
       if (tryDecodeInst(DecoderTableGFX940128, MI, DecW, Address, CS))
         break;
 
diff --git a/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.h b/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.h
index 8927f208fd2af..90399a9483877 100644
--- a/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.h
+++ b/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.h
@@ -32,44 +32,6 @@ class MCOperand;
 class MCSubtargetInfo;
 class Twine;
 
-// Exposes an interface expected by autogenerated code in
-// FixedLenDecoderEmitter
-class DecoderUInt128 {
-private:
-  uint64_t Lo = 0;
-  uint64_t Hi = 0;
-
-public:
-  DecoderUInt128() = default;
-  DecoderUInt128(uint64_t Lo, uint64_t Hi = 0) : Lo(Lo), Hi(Hi) {}
-  operator bool() const { return Lo || Hi; }
-  uint64_t extractBitsAsZExtValue(unsigned NumBits,
-                                  unsigned BitPosition) const {
-    assert(NumBits && NumBits <= 64);
-    assert(BitPosition < 128);
-    uint64_t Val;
-    if (BitPosition < 64)
-      Val = Lo >> BitPosition | Hi << 1 << (63 - BitPosition);
-    else
-      Val = Hi >> (BitPosition - 64);
-    return Val & ((uint64_t(2) << (NumBits - 1)) - 1);
-  }
-  DecoderUInt128 operator&(const DecoderUInt128 &RHS) const {
-    return DecoderUInt128(Lo & RHS.Lo, Hi & RHS.Hi);
-  }
-  DecoderUInt128 operator&(const uint64_t &RHS) const {
-    return *this & DecoderUInt128(RHS);
-  }
-  DecoderUInt128 operator~() const { return DecoderUInt128(~Lo, ~Hi); }
-  bool operator==(const DecoderUInt128 &RHS) {
-    return Lo == RHS.Lo && Hi == RHS.Hi;
-  }
-  bool operator!=(const DecoderUInt128 &RHS) {
-    return Lo != RHS.Lo || Hi != RHS.Hi;
-  }
-  bool operator!=(const int &RHS) { return *this != DecoderUInt128(RHS); }
-};
-
 //===----------------------------------------------------------------------===//
 // AMDGPUDisassembler
 //===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/ARM/ARM.td b/llvm/lib/Target/ARM/ARM.td
index 570aae9b3c7a7..d21d5d988d19a 100644
--- a/llvm/lib/Target/ARM/ARM.td
+++ b/llvm/lib/Target/ARM/ARM.td
@@ -38,7 +38,9 @@ include "ARMSchedule.td"
 //===----------------------------------------------------------------------===//
 
 include "ARMInstrInfo.td"
-def ARMInstrInfo : InstrInfo;
+def ARMInstrInfo : InstrInfo {
+  let GenerateTemplatedDecoder = false;
+}
 
 //===----------------------------------------------------------------------===//
 // ARM schedules
diff --git a/llvm/lib/Target/M68k/M68k.td b/llvm/lib/Target/M68k/M68k.td
index dab66d1022955..0a8f0acd1c336 100644
--- a/llvm/lib/Target/M68k/M68k.td
+++ b/llvm/lib/Target/M68k/M68k.td
@@ -95,7 +95,9 @@ include "GISel/M68kRegisterBanks.td"
 
 include "M68kInstrInfo.td"
 
-def M68kInstrInfo : InstrInfo;
+def M68kInstrInfo : InstrInfo {
+  let GenerateTemplatedDecoder = false;
+}
 
 //===----------------------------------------------------------------------===//
 // Calling Conventions
diff --git a/llvm/test/TableGen/DecoderEmitterFnTable.td b/llvm/test/TableGen/DecoderEmitterFnTable.td
index 837ec3bdc5c84..ebef1cf3c10c9 100644
--- a/llvm/test/TableGen/DecoderEmitterFnTable.td
+++ b/llvm/test/TableGen/DecoderEmitterFnTable.td
@@ -71,14 +71,14 @@ def Inst3 : TestInstruction {
   let AsmString = "Inst3";
 }
 
-// CHECK-LABEL: DecodeStatus decodeFn0(DecodeStatus S, const InsnType &insn, MCInst &MI, uint64_t Address, const MCDisassembler *Decoder, bool &DecodeComplete)
-// CHECK-LABEL: DecodeStatus decodeFn1(DecodeStatus S, const InsnType &insn, MCInst &MI, uint64_t Address, const MCDisassembler *Decoder, bool &DecodeComplete)
-// CHECK-LABEL: DecodeStatus decodeFn2(DecodeStatus S, const InsnType &insn, MCInst &MI, uint64_t Address, const MCDisassembler *Decoder, bool &DecodeComplete)
-// CHECK-LABEL: DecodeStatus decodeFn3(DecodeStatus S, const InsnType &insn, MCInst &MI, uint64_t Address, const MCDisassembler *Decoder, bool &DecodeComplete)
+// CHECK-LABEL: DecodeStatus decodeFn_0(DecodeStatus S, const InsnType &insn, MCInst &MI, uint64_t Address, const MCDisassembler *Decoder, bool &DecodeComplete)
+// CHECK-LABEL: DecodeStatus decodeFn_1(DecodeStatus S, const InsnType &insn, MCInst &MI, uint64_t Address, const MCDisassembler *Decoder, bool &DecodeComplete)
+// CHECK-LABEL: DecodeStatus decodeFn_2(DecodeStatus S, const InsnType &insn, MCInst &MI, uint64_t Address, const MCDisassembler *Decoder, bool &DecodeComplete)
+// CHECK-LABEL: DecodeStatus decodeFn_3(DecodeStatus S, const InsnType &insn, MCInst &MI, uint64_t Address, const MCDisassembler *Decoder, bool &DecodeComplete)
 // CHECK-LABEL: decodeToMCInst(unsigned Idx, DecodeStatus S, const InsnType &insn, MCInst &MI, uint64_t Address, const MCDisassembler *Decoder, bool &DecodeComplete)
 // CHECK: static constexpr DecodeFnTy decodeFnTable[]
-// CHECK-NEXT: decodeFn0,
-// CHECK-NEXT: decodeFn1,
-// CHECK-NEXT: decodeFn2,
-// CHECK-NEXT: decodeFn3,
+// CHECK-NEXT: decodeFn_0,
+// CHECK-NEXT: decodeFn_1,
+// CHECK-NEXT: decodeFn_2,
+// CHECK-NEXT: decodeFn_3,
 // CHECK: return decodeFnTable[Idx](S, insn, MI, Address, Decoder, DecodeComplete)
diff --git a/llvm/utils/TableGen/Common/Types.cpp b/llvm/utils/TableGen/Common/Types.cpp
index 35b79b320dc32..3d2a1e5f6bb69 100644
--- a/llvm/utils/TableGen/Common/Types.cpp
+++ b/llvm/utils/TableGen/Common/Types.cpp
@@ -36,3 +36,15 @@ llvm::getMinimalTypeForRange(uint64_t Range,
     return "uint16_t";
   return "uint8_t";
 }
+
+std::string llvm::getTypeForBitwidth(unsigned Bitwidth) {
+  if (Bitwidth <= 8)
+    return "uint8_t";
+  if (Bitwidth <= 16)
+    return "uint16_t";
+  if (Bitwidth <= 32)
+    return "uint32_t";
+  if (Bitwidth <= 64)
+    return "uint64_t";
+  return "std::bitset<" + std::to_string(Bitwidth) + ">";
+}
diff --git a/llvm/utils/TableGen/Common/Types.h b/llvm/utils/TableGen/Common/Types.h
index 073b91f8ab28a..c7613d2d629d7 100644
--- a/llvm/utils/TableGen/Common/Types.h
+++ b/llvm/utils/TableGen/Common/Types.h
@@ -10,12 +10,17 @@
 #define LLVM_UTILS_TABLEGEN_COMMON_TYPES_H
 
 #include <cstdint>
+#include <string>
 
 namespace llvm {
 /// Returns the smallest unsigned integer type that can hold the given range.
 /// MaxSize indicates the largest size of integer to consider (in bits) and only
 /// supports values of at least 32.
 const char *getMinimalTypeForRange(uint64_t Range, unsigned MaxSize = 64);
+
+/// Returns the smallest unsigned integer type that can hold integers of the
+/// given bit width. For bit width > 64, returns appropriate bitset type.
+std::string getTypeForBitwidth(unsigned Bitwidth);
 } // namespace llvm
 
 #endif // LLVM_UTILS_TABLEGEN_COMMON_TYPES_H
diff --git a/llvm/utils/TableGen/DecoderEmitter.cpp b/llvm/utils/TableGen/DecoderEmitter.cpp
index ba4bab9793eb1..32804091da412 100644
--- a/llvm/utils/TableGen/DecoderEmitter.cpp
+++ b/llvm/utils/TableGen/DecoderEmitter.cpp
@@ -15,6 +15,7 @@
 #include "Common/CodeGenInstruction.h"
 #include "Common/CodeGenTarget.h"
 #include "Common/InfoByHwMode.h"
+#include "Common/Types.h"
 #include "Common/VarLenCodeEmitterGen.h"
 #include "TableGenBackends.h"
 #include "llvm/ADT/APInt.h"
@@ -217,17 +218,6 @@ struct EncodingIDAndOpcode {
 using EncodingIDsVec = std::vector<EncodingIDAndOpcode>;
 using NamespacesHwModesMap = std::map<std::string, std::set<StringRef>>;
 
-// Result of parsing the `InsnCPPTypes` and `InstBitwidths` fields in the Target
-// instruction set.
-using BitwidthSet = SmallSet<unsigned, 4>;
-struct NonTemplatedInsnType {
-  StringRef CPPType;
-  BitwidthSet Bitwidths;
-
-  NonTemplatedInsnType(StringRef CPPType, BitwidthSet Bitwidths)
-      : CPPType(CPPType), Bitwidths(std::move(Bitwidths)) {}
-};
-
 class DecoderEmitter {
   const RecordKeeper &RK;
   std::vector<EncodingAndInst> NumberedEncodings;
@@ -244,16 +234,15 @@ class DecoderEmitter {
   void emitInstrLenTable(formatted_raw_ostream &OS,
                          ArrayRef<unsigned> InstrLen) const;
   void emitPredicateFunction(formatted_raw_ostream &OS,
-                             PredicateSet &Predicates, indent Indent) const;
+                             PredicateSet &Predicates) const;
   void emitDecoderFunction(formatted_raw_ostream &OS, DecoderSet &Decoders,
-                           StringRef SpecializedInsnType, indent Indent) const;
+                           StringRef SpecializedInsnType,
+                           StringRef Suffix) const;
 
   // run - Output the code emitter
   void run(raw_ostream &o);
 
 private:
-  SmallVector<NonTemplatedInsnType>
-  parseNonTemplatedInsnTypes(BitwidthSet &InstrBitwidths);
   CodeGenTarget Target;
 
 public:
@@ -1062,22 +1051,19 @@ void DecoderEmitter::emitInstrLenTable(formatted_raw_ostream &OS,
 }
 
 void DecoderEmitter::emitPredicateFunction(formatted_raw_ostream &OS,
-                                           PredicateSet &Predicates,
-                                           indent Indent) const {
+                                           PredicateSet &Predicates) const {
   // The predicate function is just a big switch statement based on the
   // input predicate index.
-  OS << Indent << "static bool checkDecoderPredicate(unsigned Idx, "
+  OS << "static bool checkDecoderPredicate(unsigned Idx, "
      << "const FeatureBitset &Bits) {\n";
-  Indent += 2;
-  OS << Indent << "switch (Idx) {\n";
-  OS << Indent << "default: llvm_unreachable(\"Invalid index!\");\n";
+  OS << "  switch (Idx) {\n";
+  OS << "    default: llvm_unreachable(\"Invalid index!\");\n";
   for (const auto &[Index, Predicate] : enumerate(Predicates)) {
-    OS << Indent << "case " << Index << ":\n";
-    OS << Indent + 2 << "return (" << Predicate << ");\n";
+    OS << "    case " << Index << ":\n";
+    OS << "       return (" << Predicate << ");\n";
   }
-  OS << Indent << "}\n";
-  Indent -= 2;
-  OS << Indent << "}\n\n";
+  OS << "  }\n";
+  OS << "}\n\n";
 }
 
 static void emitTemplate(formatted_raw_ostream &OS,
@@ -1093,10 +1079,9 @@ static StringRef getInsnType(StringRef SpecializedInsnType) {
 void DecoderEmitter::emitDecoderFunction(formatted_raw_ostream &OS,
                                          DecoderSet &Decoders,
                                          StringRef SpecializedInsnType,
-                                         indent Indent) const {
+                                         StringRef Suffix) const {
   // The decoder function is just a big switch statement or a table of function
   // pointers based on the input decoder index.
-
   StringRef InsnType = getInsnType(SpecializedInsnType);
 
   // TODO: When InsnType is large, using uint64_t limits all fields to 64 bits
@@ -1106,61 +1091,59 @@ void DecoderEmitter::emitDecoderFunction(formatted_raw_ostream &OS,
       "using TmpType = std::conditional_t<std::is_integral<{0}>::value, {0}, "
       "uint64_t>;\n",
       InsnType);
+
+  // Use a reference for `insn` parameter if its not a standard integer type.
+  StringRef Reference = InsnType.starts_with("uint") ? "" : "&";
+
   auto DecodeParams =
-      formatv("DecodeStatus S, const {} &insn, MCInst &MI, uint64_t Address, "
+      formatv("DecodeStatus S, const {} {}insn, MCInst &MI, uint64_t Address, "
               "const MCDisassembler *Decoder, bool &DecodeComplete",
-              InsnType);
+              InsnType, Reference);
 
   if (UseFnTableInDecodeToMCInst) {
     // Emit a function for each case first.
     for (const auto &[Index, Decoder] : enumerate(Decoders)) {
       emitTemplate(OS, SpecializedInsnType);
-      OS << Indent << "DecodeStatus decodeFn" << Index << "(" << DecodeParams
-         << ") {\n";
-      Indent += 2;
-      OS << Indent << TmpTypeDecl;
-      OS << Indent << "[[maybe_unused]] TmpType tmp;\n";
+      OS << "DecodeStatus decodeFn" << Suffix << '_' << Index << "("
+         << DecodeParams << ") {\n";
+      OS << "  " << TmpTypeDecl;
+      OS << "  [[maybe_unused]] TmpType tmp;\n";
       OS << Decoder;
-      OS << Indent << "return S;\n";
-      Indent -= 2;
-      OS << Indent << "}\n\n";
+      OS << "  return S;\n";
+      OS << "}\n\n";
     }
   }
 
-  OS << Indent << "// Handling " << Decoders.size() << " cases.\n";
+  OS << "// Handling " << Decoders.size() << " cases.\n";
   emitTemplate(OS, SpecializedInsnType);
-  OS << Indent << "static DecodeStatus decodeToMCInst(unsigned Idx, "
+  OS << "static DecodeStatus decodeToMCInst" << Suffix << "(unsigned Idx, "
      << DecodeParams << ") {\n";
-  Indent += 2;
-  OS << Indent << "DecodeComplete = true;\n";
+  OS << "  DecodeComplete = true;\n";
 
   if (UseFnTableInDecodeToMCInst) {
     // Build a table of function pointers.
-    OS << Indent << "using DecodeFnTy = DecodeStatus (*)(" << DecodeParams
-       << ");\n";
-    OS << Indent << "static constexpr DecodeFnTy decodeFnTable[] = {\n";
+    OS << "  using DecodeFnTy = DecodeStatus (*)(" << DecodeParams << ");\n";
+    OS << "  static constexpr DecodeFnTy decodeFnTable[] = {\n";
     for (size_t Index : llvm::seq(Decoders.size()))
-      OS << Indent + 2 << "decodeFn" << Index << ",\n";
-    OS << Indent << "};\n";
-    OS << Indent << "if (Idx >= " << Decoders.size() << ")\n";
-    OS << Indent + 2 << "llvm_unreachable(\"Invalid index!\");\n";
-    OS << Indent
-       << "return decodeFnTable[Idx](S, insn, MI, Address, Decoder, "
+      OS << "    decodeFn" << Suffix << '_' << Index << ",\n";
+    OS << "  };\n";
+    OS << "  if (Idx >= " << Decoders.size() << ")\n";
+    OS << "    llvm_unreachable(\"Invalid index!\");\n";
+    OS << "return decodeFnTable[Idx](S, insn, MI, Address, Decoder, "
           "DecodeComplete);\n";
   } else {
-    OS << Indent << TmpTypeDecl;
-    OS << Indent << "TmpType tmp;\n";
-    OS << Indent << "switch (Idx) {\n";
-    OS << Indent << "default: llvm_unreachable(\"Invalid index!\");\n";
+    OS << "  " << TmpTypeDecl;
+    OS << "  TmpType tmp;\n";
+    OS << "  switch (Idx) {\n";
+    OS << "    default: llvm_unreachable(\"Invalid index!\");\n";
     for (const auto &[Index, Decoder] : enumerate(Decoders)) {
-      OS << Indent << "case " << Index << ":\n";
+      OS << "    case " << Index << ":\n";
       OS << Decoder;
-      OS << Indent + 2 << "return S;\n";
+      OS << "    return S;\n";
     }
-    OS << Indent << "}\n";
+    OS << "  }\n";
   }
-  Indent -= 2;
-  OS << Indent << "}\n";
+  OS << "}\n";
 }
 
 // Populates the field of the insn given the start position and the number of
@@ -2203,24 +2186,18 @@ populateInstruction(const CodeGenTarget &Target, const Record &EncodingDef,
   return Bits.getNumBits();
 }
 
-static bool isKnownIntegralType(StringRef InsnType) {
-  static constexpr StringLiteral KnownIntegralTypes[] = {"uint16_t", "uint32_t",
-                                                         "uint64_t"};
-  return llvm::is_contained(KnownIntegralTypes, InsnType);
-}
-
 // emitFieldFromInstruction - Emit the templated helper function
 // fieldFromInstruction().
 // On Windows we make sure that this function is not inlined when
 // using the VS compiler. It has a bug which causes the function
 // to be optimized out in some circumstances. See llvm.org/pr38292
 static void emitFieldFromInstruction(formatted_raw_ostream &OS,
-                                     StringRef SpecializedInsnType) {
+                                     bool IsTemplated, bool IsVarLenInst) {
   OS << R"(
 // Helper functions for extracting fields from encoded instructions.
 // InsnType must either be integral or an APInt-like object that must:
 // * be default-constructible and copy-constructible
-// * Support extractBitsAsZExtValue(numBits, startBit)
+// * Support extractBitsAsZExtValue(Size, StartBit)
 // * Support the ~, &, ==, and != operators with other objects of the same type
 // * Support the != and bitwise & with uint64_t
 
@@ -2231,75 +2208,53 @@ static void emitFieldFromInstruction(formatted_raw_ostream &OS,
 #define DEC_EMIT_NO_INLINE
 #endif
 
-)";
-  StringRef InsnType = getInsnType(SpecializedInsnType);
-
-  // If InsnType is not a template type argument, we cannot use std::enable_if_t
-  // to enable or disable one of the versions of `fieldFromInstruction`. Use a
-  // set if pre-defined strings to detect which version of
-  // `fieldFromInstruction` to emit.
-  bool IsIntegralType = isKnownIntegralType(InsnType);
-  bool GenerateTemplatedForm = SpecializedInsnType.empty();
-
-  if (GenerateTemplatedForm || IsIntegralType) {
-    if (GenerateTemplatedForm) {
-      emitTemplate(OS, SpecializedInsnType);
-      OS << formatv("DEC_EMIT_NO_INLINE static "
-                    "std::enable_if_t<std::is_integral<{0}>::value, {0}>\n",
-                    InsnType);
-    } else {
-      OS << formatv("DEC_EMIT_NO_INLINE static {} ", InsnType);
-    }
-
-    OS << formatv(
-        R"(fieldFromInstruction(const {0} &insn, unsigned startBit, unsigned numBits) {{
-  assert(startBit + numBits <= 64 && "Cannot support >64-bit extractions!");
-  assert(startBit + numBits <= (sizeof({0}) * 8) &&
+// This is the version that works with integeral types, and its always emitted.
+template <typename IntType>
+DEC_EMIT_NO_INLINE static 
+std::enable_if_t<std::is_integral_v<IntType>, IntType>
+fieldFromInstruction(const IntType &Insn, unsigned StartBit, unsigned Size) {
+  assert(StartBit + Size <= 64 && "Cannot support >64-bit extractions!");
+  assert(StartBit + Size <= (sizeof(IntType) * 8) &&
          "Instruction field out of bounds!");
-  {0} fieldMask;
-  if (numBits == sizeof({0}) * 8)
-    fieldMask = ({0})(-1LL);
+  IntType fieldMask;
+  if (Size == sizeof(IntType) * 8)
+    fieldMask = (IntType)(-1LL);
   else
-    fieldMask = ((({0})1 << numBits) - 1) << startBit;
-  return (insn & fieldMask) >> startBit;
+    fieldMask = (((IntType)1 << Size) - 1) << StartBit;
+  return (Insn & fieldMask) >> StartBit;
 }
 
-)",
-        InsnType);
-  } // if (GenerateTemplatedForm || IsIntegralType) {
-
-  if (GenerateTemplatedForm || !IsIntegralType) {
-    if (GenerateTemplatedForm) {
-      emitTemplate(OS, SpecializedInsnType);
-      OS << formatv(
-          "static std::enable_if_t<!std::is_integral<{0}>::value, uint64_t>\n",
-          InsnType);
-    } else {
-      OS << formatv("static uint64_t ");
-    }
-
-    OS << formatv(R"(fieldFromInstruction(const {0} &insn, unsigned startBit,
-                     unsigned numBits) {{
-  return insn.extractBitsAsZExtValue(numBits, startBit);
+)";
+  if (IsVarLenInst || IsTemplated) {
+    // The templated version also works with APIntType.
+    OS << R"(
+template <typename InsnType>
+static std::enable_if_t<!std::is_integral_v<InsnType>, uint64_t>
+fieldFromInstruction(const InsnType &Insn, unsigned StartBit,
+                     unsigned Size) {
+  return Insn.extractBitsAsZExtValue(Size, StartBit);
+}
+)";
+  } else {
+    // Emit a version that will work with a std::bitset.
+    OS << R"(
+template <size_t N>
+uint64_t fieldFromInstruction(const std::bitset<N>& Insn, unsigned StartBit,
+                              unsigned Size) {
+  assert(StartBit + Size <= N && "Instruction field out of bounds!");
+  assert(Size <= 64 && "Cannot support >64-bit extractions!");
+  if (Size == N)
+    return Insn.to_ullong();
+  const std::bitset<N> Mask((1ULL << Size) - 1);
+  return ((Insn >> StartBit) & Mask).to_ullong();
 }
-)",
-                  InsnType);
-  } // if (GenerateTemplatedForm || !IsIntegralType)
-  OS << "#undef DEC_EMIT_NO_INLINE\n";
+)";
+  }
+  OS << "#undef DEC_EMIT_NO_INLINE\n\n";
 }
 
-// emitInsertBits - Emit the templated helper function insertBits().
-static void emitInsertBits(formatted_raw_ostream &OS,
-                           StringRef SpecializedInsnType) {
-  bool GenerateTemplatedForm = SpecializedInsnType.empty();
-  StringRef InsnType = getInsnType(SpecializedInsnType);
-  bool IsIntegralType = isKnownIntegralType(InsnType);
-
-  auto FuncDecl = formatv(R"([[maybe_unused]]
-static void insertBits({0} &field, {0} bits, unsigned startBit,
-                       unsigned numBits) {{)",
-                          InsnType);
-
+// emitInsertBits - Emit the helper function insertBits().
+static void emitInsertBits(formatted_raw_ostream &OS) {
   OS << R"(
 // Helper function for inserting bits extracted from an encoded instruction into
 // an integer-typed field.
@@ -2314,13 +2269,14 @@ insertBits(IntType &field, IntType bits, unsigned startBit, unsigned numBits) {
   (void)numBits;
   field |= bits << startBit;
 }
-)",
+)";
 }
 
 // emitDecodeInstruction - Emit the entry function function decodeInstruction().
 static void emitDecodeInstruction(formatted_raw_ostream &OS, bool IsVarLenInst,
                                   unsigned OpcodeMask,
-                                  StringRef SpecializedInsnType) {
+                                  StringRef SpecializedInsnType,
+                                  StringRef Suffix) {
   const bool HasTryDecode = OpcodeMask & ((1 << MCD::OPC_TryDecode) |
                                           (1 << MCD::OPC_TryDecodeOrFail));
   const bool HasCheckPredicate =
@@ -2330,24 +2286,25 @@ static void emitDecodeInstruction(formatted_raw_ostream &OS, bool IsVarLenInst,
 
   StringRef InsnType = getInsnType(SpecializedInsnType);
 
-  emitTemplate(OS, SpecializedInsnType);
-  OS << R"(
-static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], MCInst &MI, )";
+  // Use a reference for `insn` parameter if its not a standard integer type.
+  StringRef Reference = InsnType.starts_with("uint") ? "" : "&";
+
   // For variable length instructions, use a non-const reference to match the
   // signature of the `makeUp` function passed in.
-  if (IsVarLenInst)
-    OS << InsnType << " &insn,";
-  else
-    OS << "const " << InsnType << " &insn,";
-  OS << R"(
-                                      uint64_t Address,
-                                      const MCDisassembler *DisAsm,
-                                      const MCSubtargetInfo &STI)";
-  if (IsVarLenInst) {
-    OS << ",\n                                      "
-          "llvm::function_ref<void(APInt &, uint64_t)> makeUp";
-  }
-  OS << ") {\n";
+  StringRef Const = IsVarLenInst ? "" : "const ";
+
+  auto emitFn = [&](StringRef FnSuffix) {
+    OS << formatv("static DecodeStatus decodeInstruction{}(const uint8_t "
+                  "DecodeTable[], MCInst &MI, {}{} {}insn, uint64_t Address, "
+                  "const MCDisassembler *DisAsm, const MCSubtargetInfo &STI",
+                  FnSuffix, Const, InsnType, Reference);
+    if (IsVarLenInst)
+      OS << ", llvm::function_ref<void(APInt &, uint64_t)> makeUp";
+    OS << ") {\n";
+  };
+
+  emitTemplate(OS, SpecializedInsnType);
+  emitFn(Suffix);
   if (HasCheckPredicate)
     OS << "  const FeatureBitset &Bits = STI.getFeatureBits();\n";
 
@@ -2471,19 +2428,20 @@ static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], MCInst &MI, )
     OS << "\n      unsigned Len = InstrLenTable[Opc];\n"
        << "      makeUp(insn, Len);";
   }
-  OS << R"(
-      S = decodeToMCInst(DecodeIdx, S, insn, MI, Address, DisAsm, DecodeComplete);
+  OS << formatv(R"(
+      S = decodeToMCInst{}(DecodeIdx, S, insn, MI, Address, DisAsm, DecodeComplete);
       assert(DecodeComplete);
 
       LLVM_DEBUG(dbgs() << Loc << ": OPC_Decode: opcode " << Opc
                    << ", using decoder " << DecodeIdx << ": "
                    << (S != MCDisassembler::Fail ? "PASS\n" : "FAIL\n"));
       return S;
-    })";
+    })",
+                Suffix);
   if (HasTryDecode) {
-    OS << R"(
+    OS << formatv(R"(
     case MCD::OPC_TryDecode:
-    case MCD::OPC_TryDecodeOrFail: {
+    case MCD::OPC_TryDecodeOrFail: {{
       bool IsFail = DecoderOp == MCD::OPC_TryDecodeOrFail;
       // Decode the Opcode value.
       unsigned Opc = decodeULEB128AndIncUnsafe(Ptr);
@@ -2494,18 +2452,18 @@ static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], MCInst &MI, )
       MCInst TmpMI;
       TmpMI.setOpcode(Opc);
       bool DecodeComplete;
-      S = decodeToMCInst(DecodeIdx, S, insn, TmpMI, Address, DisAsm, DecodeComplete);
+      S = decodeToMCInst{}(DecodeIdx, S, insn, TmpMI, Address, DisAsm, DecodeComplete);
       LLVM_DEBUG(dbgs() << Loc << ": OPC_TryDecode: opcode " << Opc
                    << ", using decoder " << DecodeIdx << ": ");
 
-      if (DecodeComplete) {
+      if (DecodeComplete) {{
         // Decoding complete.
         LLVM_DEBUG(dbgs() << (S != MCDisassembler::Fail ? "PASS\n" : "FAIL\n"));
         MI = TmpMI;
         return S;
       }
       assert(S == MCDisassembler::Fail);
-      if (IsFail) {
+      if (IsFail) {{
         LLVM_DEBUG(dbgs() << "FAIL: returning FAIL\n");
         return MCDisassembler::Fail;
       }
@@ -2516,7 +2474,8 @@ static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], MCInst &MI, )
       // set before the decode attempt.
       S = MCDisassembler::Success;
       break;
-    })";
+    })",
+                  Suffix);
   }
   if (HasSoftFail) {
     OS << R"(
@@ -2542,6 +2501,19 @@ static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], MCInst &MI, )
 }
 
 )";
+
+  if (!Suffix.empty()) {
+    // Emit function without the suffix.
+    emitFn("");
+    OS << formatv(
+        "  return decodeInstruction{}(DecodeTable, MI, insn, Address, "
+        "DisAsm, STI",
+        Suffix);
+    if (IsVarLenInst)
+      OS << ", makeUp";
+    OS << ");\n";
+    OS << "}\n\n";
+  }
 }
 
 static void emitCommonFunctions(formatted_raw_ostream &OS) {
@@ -2633,64 +2605,6 @@ handleHwModesUnrelatedEncodings(const CodeGenInstruction *Instr,
     break;
   }
 }
-SmallVector<NonTemplatedInsnType>
-DecoderEmitter::parseNonTemplatedInsnTypes(BitwidthSet &InstrBitwidths) {
-  SmallVector<NonTemplatedInsnType> Parsed;
-
-  const Record *InstructionSet = Target.getInstructionSet();
-  std::vector<const Record *> DecoderOptions =
-      InstructionSet->getValueAsListOfDefs("DecoderOptions");
-
-  if (DecoderOptions.empty()) {
-    // If no `DecoderOptions` is specified in the instruction info, create one
-    // with empty values, which will trigger generation of a template code.
-    Parsed.emplace_back(StringRef(""), BitwidthSet{});
-    return Parsed;
-  }
-
-  Parsed.reserve(DecoderOptions.size());
-  BitwidthSet OptionBitwidths;
-
-  for (const Record *Option : DecoderOptions) {
-    // Use field locations for error reporting.
-    SMLoc CPPTypesLoc = Option->getFieldLoc("CPPType");
-    SMLoc BitwidthsLoc = Option->getFieldLoc("Bitwidths");
-
-    StringRef CPPType = Option->getValueAsString("CPPType");
-    if (CPPType.empty())
-      PrintFatalError(CPPTypesLoc,
-                      "CPP Type cannot be empty in `InsnCPPTypes`");
-
-    const ListInit *BWL = Option->getValueAsListInit("Bitwidths");
-    if (!BWL || BWL->empty())
-      PrintFatalError(BitwidthsLoc,
-                      "No bitwidths specified for CPPType : " + CPPType);
-
-    BitwidthSet Bitwidths;
-    for (int64_t Bitwidth : BWL->getAsListOfInts()) {
-      if (!OptionBitwidths.insert(Bitwidth).second)
-        PrintFatalError(BitwidthsLoc,
-                        "Bitwidth " + Twine(Bitwidth) + " already specified.");
-
-      if (!InstrBitwidths.contains(Bitwidth))
-        PrintFatalError(BitwidthsLoc, "No instruction of bitwidth " +
-                                          Twine(Bitwidth) + " supported.");
-      InstrBitwidths.erase(Bitwidth);
-      Bitwidths.insert(Bitwidth);
-    }
-    Parsed.emplace_back(CPPType, Bitwidths);
-  }
-
-  if (!InstrBitwidths.empty()) {
-    // FIXME: Add PrintFatalError that accepts a location and a function_ref.
-    PrintFatalError([&InstrBitwidths](raw_ostream &OS) {
-      OS << "Bitwidth(s) ";
-      interleaveComma(InstrBitwidths, OS);
-      OS << " missing in `InsnBitwidths`";
-    });
-  }
-  return Parsed;
-}
 
 // Emits disassembler code for instruction decoding.
 void DecoderEmitter::run(raw_ostream &o) {
@@ -2704,11 +2618,13 @@ void DecoderEmitter::run(raw_ostream &o) {
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/TargetParser/SubtargetFeature.h"
 #include <assert.h>
+#include <bitset>
 
 namespace {
 )";
 
   emitCommonFunctions(OS);
+  emitInsertBits(OS);
 
   Target.reverseBitsForLittleEndianEncoding();
 
@@ -2807,46 +2723,43 @@ namespace {
   if (IsVarLenInst)
     emitInstrLenTable(OS, InstrLen);
 
-  // Collect all allowed Bitwidths for instructions.
-  BitwidthSet InstrBitwidths;
-  for (const auto &[NSAndByteSize, _] : OpcMap) {
-    const unsigned Bitwidth = 8 * NSAndByteSize.second;
-    InstrBitwidths.insert(Bitwidth);
-  }
-  SmallVector<NonTemplatedInsnType> NonTemplatedInsnTypes =
-      parseNonTemplatedInsnTypes(InstrBitwidths);
+  const bool GenerateTemplated =
+      Target.getInstructionSet()->getValueAsBit("GenerateTemplatedDecoder");
+
+  emitFieldFromInstruction(OS, GenerateTemplated, IsVarLenInst);
 
   DecoderTableInfo TableInfo;
   bool HasCheckPredicate = false;
-  for (const auto &[NTType, NTBitwidths] : NonTemplatedInsnTypes) {
+
+  // Helper lambda to emit the decoder code for a given instruction Bitwidth
+  // and associated C++ type. If `Bitwidth` is 0 (and CPPType is empty) it will
+  // generate templated decoder code.
+  auto emitDecoder = [&](unsigned Bitwidth, StringRef CPPType,
+                         StringRef Suffix) {
     // Reset the Decoders for each non-templated type.
     TableInfo.Decoders.clear();
     unsigned OpcodeMask = 0;
 
-    if (!NTType.empty()) {
+    if (!CPPType.empty()) {
       OS << "// ------------------------------------------------------------\n";
-      OS << "// Decoder tables and functions for bitwidths: ";
-      interleaveComma(NTBitwidths, OS);
-      OS << "\n// Using InsnType = " << NTType << '\n';
+      OS << "// Decoder tables and functions for " << Bitwidth
+         << "-bit instructions.\n";
+      OS << "// Using C++ type `" << CPPType << "` for payload.\n\n";
     }
 
-    emitFieldFromInstruction(OS, NTType);
-    emitInsertBits(OS, NTType);
-
     for (const auto &[NSAndByteSize, EncodingIDs] : OpcMap) {
       const std::string &DecoderNamespace = NSAndByteSize.first;
       const unsigned InstrBitwidth =
           IsVarLenInst ? MaxInstLen : 8 * NSAndByteSize.second;
 
-      // Only handle instruction of the non-templated bitwidth size when
-      // non-templated bitwidth option is enabled.
-      if (!NTBitwidths.empty() && !NTBitwidths.contains(InstrBitwidth))
+      if (Bitwidth != 0 && InstrBitwidth != Bitwidth)
         continue;
 
-      // Emit the decoder for this namespace+width combination.
+      // Emit the decoder table for this namespace+ bitwidth combination.
       FilterChooser FC(NumberedEncodings, EncodingIDs, Operands,
                        IsVarLenInst ? MaxInstLen : InstrBitwidth, this);
 
+      // FIXME: Update this comment.
       // The decode table is cleared for each top level decoder function. The
       // predicates and decoders themselves, however, are shared across all
       // decoders to give more opportunities for uniqueing.
@@ -2854,6 +2767,7 @@ namespace {
       TableInfo.FixupStack.clear();
       TableInfo.FixupStack.emplace_back();
       FC.emitTableEntries(TableInfo);
+
       // Any NumToSkip fixups in the top level scope can resolve to the
       // OPC_Fail at the end of the table.
       assert(TableInfo.FixupStack.size() == 1 && "fixup stack phasing error!");
@@ -2869,18 +2783,55 @@ namespace {
                               DecoderNamespace, EncodingIDs);
     }
 
-    // Emit the decoder function for this BitWidth.
-    emitDecoderFunction(OS, TableInfo.Decoders, NTType, indent(0));
+    // Emit the decoder function for this Bitwidth.
+    emitDecoderFunction(OS, TableInfo.Decoders, CPPType, Suffix);
 
     HasCheckPredicate |= OpcodeMask & ((1 << MCD::OPC_CheckPredicate) |
                                        (1 << MCD::OPC_CheckPredicateOrFail));
 
-    emitDecodeInstruction(OS, IsVarLenInst, OpcodeMask, NTType);
+    emitDecodeInstruction(OS, IsVarLenInst, OpcodeMask, CPPType, Suffix);
+  };
+
+  auto InferCPPType = [IsVarLenInst](unsigned Bitwidth) -> std::string {
+    // For variable length instructions, we need to use APInt type for the
+    // instruction payload to support the `makeUp` function.
+    if (IsVarLenInst)
+      return "APInt";
+
+    switch (Bitwidth) {
+    case 8:
+      return "uint8_t";
+    case 16:
+      return "uint16_t";
+    case 32:
+      return "uint32_t";
+    case 64:
+      return "uint64_t";
+    default:
+      return "std::bitset<" + std::to_string(Bitwidth) + ">";
+    }
+  };
+
+  if (GenerateTemplated) {
+    emitDecoder(0, "", "");
+  } else {
+    // Collect all allowed Bitwidths for instructions.
+    SmallSet<unsigned, 4> InstrBitwidths;
+    for (const auto &[NSAndByteSize, _] : OpcMap) {
+      const unsigned Bitwidth = 8 * NSAndByteSize.second;
+      InstrBitwidths.insert(Bitwidth);
+    }
+    const bool AddSuffix = InstrBitwidths.size() > 1;
+    for (unsigned Bitwidth : InstrBitwidths) {
+      std::string CPPType = InferCPPType(Bitwidth);
+      std::string Suffix = AddSuffix ? std::to_string(Bitwidth) : "";
+      emitDecoder(Bitwidth, CPPType, Suffix);
+    }
   }
 
   // Emit the predicate function.
   if (HasCheckPredicate)
-    emitPredicateFunction(OS, TableInfo.Predicates, indent(0));
+    emitPredicateFunction(OS, TableInfo.Predicates);
 
   OS << "\n} // namespace\n";
 }
diff --git a/llvm/utils/TableGen/SearchableTableEmitter.cpp b/llvm/utils/TableGen/SearchableTableEmitter.cpp
index d17d90b452bd7..a9f98a1e4e22a 100644
--- a/llvm/utils/TableGen/SearchableTableEmitter.cpp
+++ b/llvm/utils/TableGen/SearchableTableEmitter.cpp
@@ -15,6 +15,7 @@
 
 #include "Basic/CodeGenIntrinsics.h"
 #include "Common/CodeGenTarget.h"
+#include "Common/Types.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/MapVector.h"
@@ -178,14 +179,9 @@ class SearchableTableEmitter {
     }
     if (const auto *BI = dyn_cast<BitsRecTy>(Field.RecType)) {
       unsigned NumBits = BI->getNumBits();
-      if (NumBits <= 8)
-        return "uint8_t";
-      if (NumBits <= 16)
-        return "uint16_t";
-      if (NumBits <= 32)
-        return "uint32_t";
       if (NumBits <= 64)
-        return "uint64_t";
+        return getTypeForBitwidth(NumBits);
+
       PrintFatalError(Index.Loc, Twine("In table '") + Table.Name +
                                      "' lookup method '" + Index.Name +
                                      "', key field '" + Field.Name +

>From 7365b730343f548f333623ebbb27e7db11843048 Mon Sep 17 00:00:00 2001
From: Rahul Joshi <rjoshi at nvidia.com>
Date: Fri, 11 Jul 2025 14:00:00 -0700
Subject: [PATCH 6/7] Revert unneeded changes

---
 llvm/include/llvm/TableGen/Record.h           |  2 -
 llvm/lib/TableGen/Record.cpp                  | 43 +++++++++----------
 llvm/utils/TableGen/Common/Types.cpp          | 12 ------
 llvm/utils/TableGen/Common/Types.h            |  5 ---
 .../utils/TableGen/SearchableTableEmitter.cpp | 10 +++--
 5 files changed, 27 insertions(+), 45 deletions(-)

diff --git a/llvm/include/llvm/TableGen/Record.h b/llvm/include/llvm/TableGen/Record.h
index d571710781d83..a2b86eb8e7cad 100644
--- a/llvm/include/llvm/TableGen/Record.h
+++ b/llvm/include/llvm/TableGen/Record.h
@@ -803,8 +803,6 @@ class ListInit final : public TypedInit,
   size_t size() const { return NumElements; }
   bool empty() const { return NumElements == 0; }
 
-  std::vector<int64_t> getAsListOfInts() const;
-
   const Init *getBit(unsigned Bit) const override {
     llvm_unreachable("Illegal bit reference off list");
   }
diff --git a/llvm/lib/TableGen/Record.cpp b/llvm/lib/TableGen/Record.cpp
index 8106609c8fa68..620928ef43dc5 100644
--- a/llvm/lib/TableGen/Record.cpp
+++ b/llvm/lib/TableGen/Record.cpp
@@ -804,15 +804,6 @@ std::string ListInit::getAsString() const {
   return Result + "]";
 }
 
-std::vector<int64_t> ListInit::getAsListOfInts() const {
-  if (!isa<IntRecTy>(getElementType()))
-    PrintFatalError("List does not contain integer values");
-  std::vector<int64_t> Ints;
-  for (const Init *I : getElements())
-    Ints.push_back(cast<IntInit>(I)->getValue());
-  return Ints;
-}
-
 const Init *OpInit::getBit(unsigned Bit) const {
   if (getType() == BitRecTy::get(getRecordKeeper()))
     return this;
@@ -3128,26 +3119,32 @@ int64_t Record::getValueAsInt(StringRef FieldName) const {
 std::vector<int64_t>
 Record::getValueAsListOfInts(StringRef FieldName) const {
   const ListInit *List = getValueAsListInit(FieldName);
-  if (!isa<IntRecTy>(List->getElementType()))
-    PrintFatalError(getLoc(),
-                    Twine("Record `") + getName() + "', field `" + FieldName +
-                        "' exists but does not have a list of ints value: " +
-                        List->getAsString());
-  return List->getAsListOfInts();
+  std::vector<int64_t> Ints;
+  for (const Init *I : List->getElements()) {
+    if (const auto *II = dyn_cast<IntInit>(I))
+      Ints.push_back(II->getValue());
+    else
+      PrintFatalError(getLoc(),
+                      Twine("Record `") + getName() + "', field `" + FieldName +
+                          "' exists but does not have a list of ints value: " +
+                          I->getAsString());
+  }
+  return Ints;
 }
 
 std::vector<StringRef>
 Record::getValueAsListOfStrings(StringRef FieldName) const {
   const ListInit *List = getValueAsListInit(FieldName);
-  if (!isa<StringRecTy>(List->getElementType()))
-    PrintFatalError(getLoc(),
-                    Twine("Record `") + getName() + "', field `" + FieldName +
-                        "' exists but does not have a list of string value: " +
-                        List->getAsString());
-
   std::vector<StringRef> Strings;
-  for (const Init *I : List->getElements())
-    Strings.push_back(cast<StringInit>(I)->getValue());
+  for (const Init *I : List->getElements()) {
+    if (const auto *SI = dyn_cast<StringInit>(I))
+      Strings.push_back(SI->getValue());
+    else
+      PrintFatalError(
+          getLoc(), Twine("Record `") + getName() + "', field `" + FieldName +
+                        "' exists but does not have a list of strings value: " +
+                        I->getAsString());
+  }
   return Strings;
 }
 
diff --git a/llvm/utils/TableGen/Common/Types.cpp b/llvm/utils/TableGen/Common/Types.cpp
index 3d2a1e5f6bb69..35b79b320dc32 100644
--- a/llvm/utils/TableGen/Common/Types.cpp
+++ b/llvm/utils/TableGen/Common/Types.cpp
@@ -36,15 +36,3 @@ llvm::getMinimalTypeForRange(uint64_t Range,
     return "uint16_t";
   return "uint8_t";
 }
-
-std::string llvm::getTypeForBitwidth(unsigned Bitwidth) {
-  if (Bitwidth <= 8)
-    return "uint8_t";
-  if (Bitwidth <= 16)
-    return "uint16_t";
-  if (Bitwidth <= 32)
-    return "uint32_t";
-  if (Bitwidth <= 64)
-    return "uint64_t";
-  return "std::bitset<" + std::to_string(Bitwidth) + ">";
-}
diff --git a/llvm/utils/TableGen/Common/Types.h b/llvm/utils/TableGen/Common/Types.h
index c7613d2d629d7..073b91f8ab28a 100644
--- a/llvm/utils/TableGen/Common/Types.h
+++ b/llvm/utils/TableGen/Common/Types.h
@@ -10,17 +10,12 @@
 #define LLVM_UTILS_TABLEGEN_COMMON_TYPES_H
 
 #include <cstdint>
-#include <string>
 
 namespace llvm {
 /// Returns the smallest unsigned integer type that can hold the given range.
 /// MaxSize indicates the largest size of integer to consider (in bits) and only
 /// supports values of at least 32.
 const char *getMinimalTypeForRange(uint64_t Range, unsigned MaxSize = 64);
-
-/// Returns the smallest unsigned integer type that can hold integers of the
-/// given bit width. For bit width > 64, returns appropriate bitset type.
-std::string getTypeForBitwidth(unsigned Bitwidth);
 } // namespace llvm
 
 #endif // LLVM_UTILS_TABLEGEN_COMMON_TYPES_H
diff --git a/llvm/utils/TableGen/SearchableTableEmitter.cpp b/llvm/utils/TableGen/SearchableTableEmitter.cpp
index a9f98a1e4e22a..d17d90b452bd7 100644
--- a/llvm/utils/TableGen/SearchableTableEmitter.cpp
+++ b/llvm/utils/TableGen/SearchableTableEmitter.cpp
@@ -15,7 +15,6 @@
 
 #include "Basic/CodeGenIntrinsics.h"
 #include "Common/CodeGenTarget.h"
-#include "Common/Types.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/MapVector.h"
@@ -179,9 +178,14 @@ class SearchableTableEmitter {
     }
     if (const auto *BI = dyn_cast<BitsRecTy>(Field.RecType)) {
       unsigned NumBits = BI->getNumBits();
+      if (NumBits <= 8)
+        return "uint8_t";
+      if (NumBits <= 16)
+        return "uint16_t";
+      if (NumBits <= 32)
+        return "uint32_t";
       if (NumBits <= 64)
-        return getTypeForBitwidth(NumBits);
-
+        return "uint64_t";
       PrintFatalError(Index.Loc, Twine("In table '") + Table.Name +
                                      "' lookup method '" + Index.Name +
                                      "', key field '" + Field.Name +

>From 1824e68602aa51b7c9ccc16f68b6c93ace4c689d Mon Sep 17 00:00:00 2001
From: Rahul Joshi <rjoshi at nvidia.com>
Date: Fri, 11 Jul 2025 16:57:12 -0700
Subject: [PATCH 7/7] Add a struct CPPType to track C++ type better

---
 .../M68k/Disassembler/M68kDisassembler.cpp    |   4 +-
 llvm/test/TableGen/VarLenDecoder.td           |   4 +-
 llvm/utils/TableGen/DecoderEmitter.cpp        | 290 +++++++++++-------
 3 files changed, 190 insertions(+), 108 deletions(-)

diff --git a/llvm/lib/Target/M68k/Disassembler/M68kDisassembler.cpp b/llvm/lib/Target/M68k/Disassembler/M68kDisassembler.cpp
index ee453cfc0924e..4ec18fe6bf544 100644
--- a/llvm/lib/Target/M68k/Disassembler/M68kDisassembler.cpp
+++ b/llvm/lib/Target/M68k/Disassembler/M68kDisassembler.cpp
@@ -111,13 +111,13 @@ static DecodeStatus DecodeFPCSCRegisterClass(MCInst &Inst, uint64_t RegNo,
 }
 #define DecodeFPICRegisterClass DecodeFPCSCRegisterClass
 
-static DecodeStatus DecodeCCRCRegisterClass(MCInst &Inst, const APInt &Insn,
+static DecodeStatus DecodeCCRCRegisterClass(MCInst &Inst, APInt &Insn,
                                             uint64_t Address,
                                             const void *Decoder) {
   llvm_unreachable("unimplemented");
 }
 
-static DecodeStatus DecodeSRCRegisterClass(MCInst &Inst, const APInt &Insn,
+static DecodeStatus DecodeSRCRegisterClass(MCInst &Inst, APInt &Insn,
                                            uint64_t Address,
                                            const void *Decoder) {
   llvm_unreachable("unimplemented");
diff --git a/llvm/test/TableGen/VarLenDecoder.td b/llvm/test/TableGen/VarLenDecoder.td
index d438e64264cbd..23d91cc6571ac 100644
--- a/llvm/test/TableGen/VarLenDecoder.td
+++ b/llvm/test/TableGen/VarLenDecoder.td
@@ -3,7 +3,9 @@
 
 include "llvm/Target/Target.td"
 
-def ArchInstrInfo : InstrInfo { }
+def ArchInstrInfo : InstrInfo {
+  let GenerateTemplatedDecoder = false;
+}
 
 def Arch : Target {
   let InstructionSet = ArchInstrInfo;
diff --git a/llvm/utils/TableGen/DecoderEmitter.cpp b/llvm/utils/TableGen/DecoderEmitter.cpp
index 32804091da412..4502f49b1d979 100644
--- a/llvm/utils/TableGen/DecoderEmitter.cpp
+++ b/llvm/utils/TableGen/DecoderEmitter.cpp
@@ -218,6 +218,20 @@ struct EncodingIDAndOpcode {
 using EncodingIDsVec = std::vector<EncodingIDAndOpcode>;
 using NamespacesHwModesMap = std::map<std::string, std::set<StringRef>>;
 
+// A struct to represent the C++ type for the instruction payload.
+struct CPPType {
+  enum TypeKind { TemplateTy, UIntTy, APIntTy, BitsetTy } Kind;
+  unsigned Bitwidth; // 0 for TemplateTy.
+
+  CPPType(unsigned Bitwidth, bool IsVarLenInst);
+
+  // Returns the C++ type name for code generation.
+  std::string getName() const;
+
+  // Returns the parameter declration for code generation.
+  std::string getParamDecl() const;
+};
+
 class DecoderEmitter {
   const RecordKeeper &RK;
   std::vector<EncodingAndInst> NumberedEncodings;
@@ -236,8 +250,7 @@ class DecoderEmitter {
   void emitPredicateFunction(formatted_raw_ostream &OS,
                              PredicateSet &Predicates) const;
   void emitDecoderFunction(formatted_raw_ostream &OS, DecoderSet &Decoders,
-                           StringRef SpecializedInsnType,
-                           StringRef Suffix) const;
+                           const CPPType &Type, StringRef Suffix) const;
 
   // run - Output the code emitter
   void run(raw_ostream &o);
@@ -1066,56 +1079,107 @@ void DecoderEmitter::emitPredicateFunction(formatted_raw_ostream &OS,
   OS << "}\n\n";
 }
 
-static void emitTemplate(formatted_raw_ostream &OS,
-                         StringRef SpecializedInsnType) {
-  if (SpecializedInsnType.empty())
-    OS << "template <typename InsnType>\n";
+// ----------------------------------------------------------------------------
+// CPPType implementation.
+
+CPPType::CPPType(unsigned Bitwidth, bool IsVarLenInst) : Bitwidth(Bitwidth) {
+  if (IsVarLenInst)
+    Kind = APIntTy;
+  else if (Bitwidth == 0)
+    Kind = TemplateTy;
+  else if (Bitwidth == 8 || Bitwidth == 16 || Bitwidth == 32 || Bitwidth == 64)
+    Kind = UIntTy;
+  else
+    Kind = BitsetTy;
+}
+
+std::string CPPType::getName() const {
+  switch (Kind) {
+  case TemplateTy:
+    return "InsnType";
+  case UIntTy:
+    return "uint" + std::to_string(Bitwidth) + "_t";
+  case APIntTy:
+    return "APInt";
+  case BitsetTy:
+    return "std::bitset<" + std::to_string(Bitwidth) + ">";
+  }
+  llvm_unreachable("Unexpected kind");
 }
 
-static StringRef getInsnType(StringRef SpecializedInsnType) {
-  return SpecializedInsnType.empty() ? "InsnType" : SpecializedInsnType;
+std::string CPPType::getParamDecl() const {
+  switch (Kind) {
+  case TemplateTy:
+  case BitsetTy:
+    return "const " + getName() + " &insn";
+  case UIntTy:
+    return getName() + " insn";
+  case APIntTy:
+    return "APInt &insn";
+  }
+  llvm_unreachable("Unexpected kind");
+}
+
+static void emitTemplate(formatted_raw_ostream &OS, const CPPType &Type) {
+  if (Type.Kind == CPPType::TemplateTy)
+    OS << "template <typename InsnType>\n";
 }
 
 void DecoderEmitter::emitDecoderFunction(formatted_raw_ostream &OS,
                                          DecoderSet &Decoders,
-                                         StringRef SpecializedInsnType,
+                                         const CPPType &Type,
                                          StringRef Suffix) const {
   // The decoder function is just a big switch statement or a table of function
   // pointers based on the input decoder index.
-  StringRef InsnType = getInsnType(SpecializedInsnType);
+  const std::string TypeName = Type.getName();
+  const std::string TypeParamDecl = Type.getParamDecl();
 
   // TODO: When InsnType is large, using uint64_t limits all fields to 64 bits
   // It would be better for emitBinaryParser to use a 64-bit tmp whenever
   // possible but fall back to an InsnType-sized tmp for truly large fields.
-  auto TmpTypeDecl = formatv(
-      "using TmpType = std::conditional_t<std::is_integral<{0}>::value, {0}, "
-      "uint64_t>;\n",
-      InsnType);
+  auto emitTmpTypeDec = [&Type, &TypeName, &OS]() {
+    if (Type.Kind == CPPType::TemplateTy)
+      OS << formatv(
+          "  using TmpType = std::conditional_t<std::is_integral<{0}>::value, "
+          "{0}, uint64_t>;\n",
+          TypeName);
+  };
 
-  // Use a reference for `insn` parameter if its not a standard integer type.
-  StringRef Reference = InsnType.starts_with("uint") ? "" : "&";
+  // Returns the type to use for the `tmp` variable.
+  StringRef TmpType = [&Type, &TypeName]() -> StringRef {
+    switch (Type.Kind) {
+    case CPPType::TemplateTy:
+      return "TmpType";
+    case CPPType::UIntTy:
+      return TypeName;
+    default:
+      return "uint64_t";
+    }
+  }();
 
   auto DecodeParams =
-      formatv("DecodeStatus S, const {} {}insn, MCInst &MI, uint64_t Address, "
+      formatv("DecodeStatus S, {}, MCInst &MI, uint64_t Address, "
               "const MCDisassembler *Decoder, bool &DecodeComplete",
-              InsnType, Reference);
+              TypeParamDecl);
 
   if (UseFnTableInDecodeToMCInst) {
     // Emit a function for each case first.
     for (const auto &[Index, Decoder] : enumerate(Decoders)) {
-      emitTemplate(OS, SpecializedInsnType);
+      emitTemplate(OS, Type);
       OS << "DecodeStatus decodeFn" << Suffix << '_' << Index << "("
          << DecodeParams << ") {\n";
-      OS << "  " << TmpTypeDecl;
-      OS << "  [[maybe_unused]] TmpType tmp;\n";
+      emitTmpTypeDec();
+      OS << "  [[maybe_unused]] " << TmpType << " tmp;\n";
       OS << Decoder;
       OS << "  return S;\n";
       OS << "}\n\n";
     }
   }
 
+  assert(!Decoders.empty() && "Did not find any decoders");
+
   OS << "// Handling " << Decoders.size() << " cases.\n";
-  emitTemplate(OS, SpecializedInsnType);
+  emitTemplate(OS, Type);
   OS << "static DecodeStatus decodeToMCInst" << Suffix << "(unsigned Idx, "
      << DecodeParams << ") {\n";
   OS << "  DecodeComplete = true;\n";
@@ -1132,8 +1196,8 @@ void DecoderEmitter::emitDecoderFunction(formatted_raw_ostream &OS,
     OS << "return decodeFnTable[Idx](S, insn, MI, Address, Decoder, "
           "DecodeComplete);\n";
   } else {
-    OS << "  " << TmpTypeDecl;
-    OS << "  TmpType tmp;\n";
+    emitTmpTypeDec();
+    OS << "  " << TmpType << " tmp;\n";
     OS << "  switch (Idx) {\n";
     OS << "    default: llvm_unreachable(\"Invalid index!\");\n";
     for (const auto &[Index, Decoder] : enumerate(Decoders)) {
@@ -2188,27 +2252,34 @@ populateInstruction(const CodeGenTarget &Target, const Record &EncodingDef,
 
 // emitFieldFromInstruction - Emit the templated helper function
 // fieldFromInstruction().
-// On Windows we make sure that this function is not inlined when
-// using the VS compiler. It has a bug which causes the function
-// to be optimized out in some circumstances. See llvm.org/pr38292
-static void emitFieldFromInstruction(formatted_raw_ostream &OS,
-                                     bool IsTemplated, bool IsVarLenInst) {
-  OS << R"(
-// Helper functions for extracting fields from encoded instructions.
-// InsnType must either be integral or an APInt-like object that must:
-// * be default-constructible and copy-constructible
-// * Support extractBitsAsZExtValue(Size, StartBit)
-// * Support the ~, &, ==, and != operators with other objects of the same type
-// * Support the != and bitwise & with uint64_t
+//
+// On Windows we make sure that this function is not inlined when using the VS
+// compiler. It has a bug which causes the function to be optimized out in some
+// circumstances. See llvm.org/pr38292
+//
+// There are 4 variants of this function that can be generated under different
+// conditions:
+//
+// 1. Integer types (for non-templated code when using integer types and when
+//                   generating templated code).
+// 2. bitset types (for non-templated code with bitset type).
+// 3. APInt type (for variable length instructions).
+// 4. Non-Integer `InsnType` (when generating templated code)
 
-// Helper macro to disable inlining of `fieldFromInstruction`.
+static void emitFieldFromInstruction(formatted_raw_ostream &OS,
+                                     bool GenerateIntType,
+                                     bool GenerateBitsetType,
+                                     bool GenerateAPIntType,
+                                     bool GenerateTemplateType) {
+  if (GenerateIntType) {
+    OS << R"(
+// Helper macro to disable inlining of `fieldFromInstruction` for integer types.
 #if defined(_MSC_VER) && !defined(__clang__)
 #define DEC_EMIT_NO_INLINE __declspec(noinline)
 #else
 #define DEC_EMIT_NO_INLINE
 #endif
 
-// This is the version that works with integeral types, and its always emitted.
 template <typename IntType>
 DEC_EMIT_NO_INLINE static 
 std::enable_if_t<std::is_integral_v<IntType>, IntType>
@@ -2223,19 +2294,12 @@ fieldFromInstruction(const IntType &Insn, unsigned StartBit, unsigned Size) {
     fieldMask = (((IntType)1 << Size) - 1) << StartBit;
   return (Insn & fieldMask) >> StartBit;
 }
+#undef DEC_EMIT_NO_INLINE
 
 )";
-  if (IsVarLenInst || IsTemplated) {
-    // The templated version also works with APIntType.
-    OS << R"(
-template <typename InsnType>
-static std::enable_if_t<!std::is_integral_v<InsnType>, uint64_t>
-fieldFromInstruction(const InsnType &Insn, unsigned StartBit,
-                     unsigned Size) {
-  return Insn.extractBitsAsZExtValue(Size, StartBit);
-}
-)";
-  } else {
+  }
+
+  if (GenerateBitsetType) {
     // Emit a version that will work with a std::bitset.
     OS << R"(
 template <size_t N>
@@ -2250,7 +2314,34 @@ uint64_t fieldFromInstruction(const std::bitset<N>& Insn, unsigned StartBit,
 }
 )";
   }
-  OS << "#undef DEC_EMIT_NO_INLINE\n\n";
+
+  if (GenerateAPIntType) {
+    // The templated version also works with APInt.
+    OS << R"(
+static uint64_t fieldFromInstruction(const APInt &Insn, unsigned StartBit,
+                     unsigned Size) {
+  return Insn.extractBitsAsZExtValue(Size, StartBit);
+}
+)";
+  }
+
+  if (GenerateTemplateType) {
+    OS << R"(
+// Helper functions for extracting fields from encoded instructions.
+// InsnType must either be integral or an APInt-like object that must:
+// * be default-constructible and copy-constructible
+// * Support extractBitsAsZExtValue(Size, StartBit)
+// * Support the ~, &, ==, and != operators with other objects of the same type
+// * Support the != and bitwise & with uint64_t
+
+template <typename InsnType>
+static std::enable_if_t<!std::is_integral_v<InsnType>, uint64_t>
+fieldFromInstruction(const InsnType &Insn, unsigned StartBit,
+                     unsigned Size) {
+  return Insn.extractBitsAsZExtValue(Size, StartBit);
+}
+)";
+  }
 }
 
 // emitInsertBits - Emit the helper function insertBits().
@@ -2274,8 +2365,7 @@ insertBits(IntType &field, IntType bits, unsigned startBit, unsigned numBits) {
 
 // emitDecodeInstruction - Emit the entry function function decodeInstruction().
 static void emitDecodeInstruction(formatted_raw_ostream &OS, bool IsVarLenInst,
-                                  unsigned OpcodeMask,
-                                  StringRef SpecializedInsnType,
+                                  unsigned OpcodeMask, const CPPType &Type,
                                   StringRef Suffix) {
   const bool HasTryDecode = OpcodeMask & ((1 << MCD::OPC_TryDecode) |
                                           (1 << MCD::OPC_TryDecodeOrFail));
@@ -2284,26 +2374,17 @@ static void emitDecodeInstruction(formatted_raw_ostream &OS, bool IsVarLenInst,
       ((1 << MCD::OPC_CheckPredicate) | (1 << MCD::OPC_CheckPredicateOrFail));
   const bool HasSoftFail = OpcodeMask & (1 << MCD::OPC_SoftFail);
 
-  StringRef InsnType = getInsnType(SpecializedInsnType);
-
-  // Use a reference for `insn` parameter if its not a standard integer type.
-  StringRef Reference = InsnType.starts_with("uint") ? "" : "&";
-
-  // For variable length instructions, use a non-const reference to match the
-  // signature of the `makeUp` function passed in.
-  StringRef Const = IsVarLenInst ? "" : "const ";
-
   auto emitFn = [&](StringRef FnSuffix) {
     OS << formatv("static DecodeStatus decodeInstruction{}(const uint8_t "
-                  "DecodeTable[], MCInst &MI, {}{} {}insn, uint64_t Address, "
+                  "DecodeTable[], MCInst &MI, {}, uint64_t Address, "
                   "const MCDisassembler *DisAsm, const MCSubtargetInfo &STI",
-                  FnSuffix, Const, InsnType, Reference);
+                  FnSuffix, Type.getParamDecl());
     if (IsVarLenInst)
       OS << ", llvm::function_ref<void(APInt &, uint64_t)> makeUp";
     OS << ") {\n";
   };
 
-  emitTemplate(OS, SpecializedInsnType);
+  emitTemplate(OS, Type);
   emitFn(Suffix);
   if (HasCheckPredicate)
     OS << "  const FeatureBitset &Bits = STI.getFeatureBits();\n";
@@ -2717,16 +2798,18 @@ namespace {
     }
   }
 
-  // For variable instruction, we emit a instruction length table
-  // to let the decoder know how long the instructions are.
-  // You can see example usage in M68k's disassembler.
-  if (IsVarLenInst)
-    emitInstrLenTable(OS, InstrLen);
-
   const bool GenerateTemplated =
       Target.getInstructionSet()->getValueAsBit("GenerateTemplatedDecoder");
 
-  emitFieldFromInstruction(OS, GenerateTemplated, IsVarLenInst);
+  // For variable instruction, we emit a instruction length table to let the
+  // decoder know how long the instructions are. You can see example usage in
+  // M68k's disassembler.
+  if (IsVarLenInst) {
+    if (GenerateTemplated)
+      PrintFatalError(
+          "Templated decoder not needed for variable length instruction");
+    emitInstrLenTable(OS, InstrLen);
+  }
 
   DecoderTableInfo TableInfo;
   bool HasCheckPredicate = false;
@@ -2734,17 +2817,16 @@ namespace {
   // Helper lambda to emit the decoder code for a given instruction Bitwidth
   // and associated C++ type. If `Bitwidth` is 0 (and CPPType is empty) it will
   // generate templated decoder code.
-  auto emitDecoder = [&](unsigned Bitwidth, StringRef CPPType,
-                         StringRef Suffix) {
+  auto emitDecoder = [&](const CPPType &Type, StringRef Suffix) {
     // Reset the Decoders for each non-templated type.
     TableInfo.Decoders.clear();
     unsigned OpcodeMask = 0;
 
-    if (!CPPType.empty()) {
+    const bool IsTemplate = Type.Kind == CPPType::TemplateTy;
+    if (!IsTemplate) {
       OS << "// ------------------------------------------------------------\n";
-      OS << "// Decoder tables and functions for " << Bitwidth
-         << "-bit instructions.\n";
-      OS << "// Using C++ type `" << CPPType << "` for payload.\n\n";
+      OS << "// Decoder tables for " << Type.Bitwidth << "-bit instructions.\n";
+      OS << "// Using C++ type `" << Type.getName() << "` for payload.\n\n";
     }
 
     for (const auto &[NSAndByteSize, EncodingIDs] : OpcMap) {
@@ -2752,7 +2834,7 @@ namespace {
       const unsigned InstrBitwidth =
           IsVarLenInst ? MaxInstLen : 8 * NSAndByteSize.second;
 
-      if (Bitwidth != 0 && InstrBitwidth != Bitwidth)
+      if (!IsTemplate && InstrBitwidth != Type.Bitwidth)
         continue;
 
       // Emit the decoder table for this namespace+ bitwidth combination.
@@ -2784,48 +2866,46 @@ namespace {
     }
 
     // Emit the decoder function for this Bitwidth.
-    emitDecoderFunction(OS, TableInfo.Decoders, CPPType, Suffix);
+    emitDecoderFunction(OS, TableInfo.Decoders, Type, Suffix);
 
     HasCheckPredicate |= OpcodeMask & ((1 << MCD::OPC_CheckPredicate) |
                                        (1 << MCD::OPC_CheckPredicateOrFail));
 
-    emitDecodeInstruction(OS, IsVarLenInst, OpcodeMask, CPPType, Suffix);
-  };
-
-  auto InferCPPType = [IsVarLenInst](unsigned Bitwidth) -> std::string {
-    // For variable length instructions, we need to use APInt type for the
-    // instruction payload to support the `makeUp` function.
-    if (IsVarLenInst)
-      return "APInt";
-
-    switch (Bitwidth) {
-    case 8:
-      return "uint8_t";
-    case 16:
-      return "uint16_t";
-    case 32:
-      return "uint32_t";
-    case 64:
-      return "uint64_t";
-    default:
-      return "std::bitset<" + std::to_string(Bitwidth) + ">";
-    }
+    emitDecodeInstruction(OS, IsVarLenInst, OpcodeMask, Type, Suffix);
   };
 
   if (GenerateTemplated) {
-    emitDecoder(0, "", "");
+    // Generate the tempated variaant of `fieldFromInstruction`.
+    emitFieldFromInstruction(
+        OS, /*GenerateIntType=*/true, /*GenerateBitsetType=*/false,
+        /*GenerateAPIntType=*/false, /*GenerateTemplateType=*/true);
+    emitDecoder(CPPType(0, false), /*Suffix=*/"");
   } else {
-    // Collect all allowed Bitwidths for instructions.
+    // Collect all allowed Bitwidths for instructions and keep track of the
+    // variants of `fieldFromInstruction` we need to generate.
     SmallSet<unsigned, 4> InstrBitwidths;
+    bool GenerateIntType = false;
+    bool GenerateBitsetType = false;
     for (const auto &[NSAndByteSize, _] : OpcMap) {
-      const unsigned Bitwidth = 8 * NSAndByteSize.second;
+      const unsigned Bitwidth =
+          IsVarLenInst ? MaxInstLen : 8 * NSAndByteSize.second;
       InstrBitwidths.insert(Bitwidth);
+      const CPPType::TypeKind Kind = CPPType(Bitwidth, IsVarLenInst).Kind;
+      GenerateIntType |= Kind == CPPType::UIntTy;
+      GenerateBitsetType |= Kind == CPPType::BitsetTy;
     }
+    assert((!IsVarLenInst || InstrBitwidths.size() == 1) &&
+           "Expect a single instruction bitwidth "
+           "for variable length instructions");
+
+    // Generate required variants of `fieldFromInstruction`.
+    emitFieldFromInstruction(OS, GenerateIntType, GenerateBitsetType,
+                             /*GenerateAPIntType=*/IsVarLenInst,
+                             /*GenerateTemplateType=*/false);
     const bool AddSuffix = InstrBitwidths.size() > 1;
     for (unsigned Bitwidth : InstrBitwidths) {
-      std::string CPPType = InferCPPType(Bitwidth);
       std::string Suffix = AddSuffix ? std::to_string(Bitwidth) : "";
-      emitDecoder(Bitwidth, CPPType, Suffix);
+      emitDecoder(CPPType(Bitwidth, IsVarLenInst), Suffix);
     }
   }
 



More information about the llvm-commits mailing list