[llvm] [TableGen][DecoderEmitter] Add option to emit type-specialized `decodeToMCInst` (PR #146593)
Rahul Joshi via llvm-commits
llvm-commits at lists.llvm.org
Thu Jul 3 19:53:25 PDT 2025
https://github.com/jurahul updated https://github.com/llvm/llvm-project/pull/146593
>From ae24279533736da279301a884a926b906778bd21 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/4] [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 d582309a6fd4a..ae3f072601014 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;
@@ -2538,6 +2566,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);
@@ -2649,35 +2741,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
@@ -2694,9 +2810,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 04366eedc71984255b2792be4ff32babd33f3668 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/4] 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 5849344bcb0b5..306988cd0fc53 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 ce9a2b2751968..e2e711baaede2 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 7f2ed77a74099..69f6fa6edb49b 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 25cdcae4e41de..670027d59acde 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 ae3f072601014..7656baddccba1 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:
@@ -2565,66 +2559,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;
@@ -2747,12 +2738,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 26588554e04dc9641c323d11fe0f0a40f230f5d7 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/4] 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 7656baddccba1..00123c62b6724 100644
--- a/llvm/utils/TableGen/DecoderEmitter.cpp
+++ b/llvm/utils/TableGen/DecoderEmitter.cpp
@@ -2261,7 +2261,8 @@ static void insertBits(InsnType &field, InsnType bits, unsigned startBit,
// 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 =
@@ -2269,6 +2270,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++;
@@ -2277,11 +2286,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) {
@@ -2802,7 +2813,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 1ecd40edc67b7222fa2a45b12a005cef94888086 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/4] 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 | 295 ++++++++++++------
10 files changed, 243 insertions(+), 154 deletions(-)
diff --git a/llvm/include/llvm/Target/Target.td b/llvm/include/llvm/Target/Target.td
index e2e711baaede2..643441bec4268 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 670027d59acde..25cdcae4e41de 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 1a1c32fba9d18..0ce66f7b88cb1 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPU.td
+++ b/llvm/lib/Target/AMDGPU/AMDGPU.td
@@ -1973,6 +1973,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 59c72fcbff18a..cd582de176c25 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 00123c62b6724..d7c37f112cd44 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:
@@ -2212,54 +2226,122 @@ static void emitFieldFromInstruction(formatted_raw_ostream &OS) {
// * Support the ~, &, ==, and != operators with other objects of the same type
// * Support the != and bitwise & with uint64_t
// * Support put (<<) to raw_ostream&
-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
// a field.
-template <typename InsnType>
-static void insertBits(InsnType &field, InsnType bits, unsigned startBit,
- unsigned numBits) {
- if constexpr (std::is_integral<InsnType>::value) {
+)";
+ if (GenerateTemplatedForm) {
+ emitTemplate(OS, SpecializedInsnType);
+ OS << FuncDecl;
+ OS << formatv(R"(
+ if constexpr (std::is_integral<{0}>::value) {{
assert(startBit + numBits <= sizeof field * 8);
(void)numBits;
- field |= (InsnType)bits << startBit;
- } else {
+ field |= ({0})bits << startBit;
+ } else {{
field.insertBits(bits, startBit, numBits);
}
}
+)",
+ InsnType);
+ } else if (IsIntegralType) {
+ OS << FuncDecl;
+ OS << formatv(R"(
+ assert(startBit + numBits <= sizeof field * 8);
+ (void)numBits;
+ field |= ({0})bits << startBit;
+}
+)",
+ InsnType);
+ } else {
+ // Code for !IsIntegralType
+ OS << FuncDecl;
+ OS << R"(
+ field.insertBits(bits, startBit, numBits);
+}
)";
+ }
+ OS << '\n';
}
-// 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) {
@@ -2270,29 +2352,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;
+ StringRef InsnType = getInsnType(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;
-})";
-
- 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) {
@@ -2496,16 +2568,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);
)";
}
@@ -2575,39 +2662,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.");
@@ -2618,7 +2702,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()) {
@@ -2648,9 +2732,7 @@ void DecoderEmitter::run(raw_ostream &o) {
namespace {
)";
- emitFieldFromInstruction(OS);
- emitInsertBits(OS);
- emitCheck(OS);
+ emitCommonFunctions(OS);
Target.reverseBitsForLittleEndianEncoding();
@@ -2700,7 +2782,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)) {
@@ -2743,6 +2825,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) {
@@ -2753,10 +2841,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;
@@ -2796,29 +2895,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";
}
More information about the llvm-commits
mailing list