[llvm] [TableGen][DecoderEmitter] Add option to emit type-specialized `decodeToMCInst` (PR #146593)
Rahul Joshi via llvm-commits
llvm-commits at lists.llvm.org
Tue Jul 15 06:51:00 PDT 2025
https://github.com/jurahul updated https://github.com/llvm/llvm-project/pull/146593
>From ebd664b61a1c5a14add604d665005c1febd737c0 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 01/12] [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 | 211 ++++++++++++++++++-----
21 files changed, 216 insertions(+), 71 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 47329b2c2f4d2..97b3755a28099 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 21c611e364a8d..d6072504f94f2 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");
@@ -232,9 +249,9 @@ class DecoderEmitter {
void emitInstrLenTable(formatted_raw_ostream &OS,
ArrayRef<unsigned> InstrLen) const;
void emitPredicateFunction(formatted_raw_ostream &OS,
- PredicateSet &Predicates) const;
- void emitDecoderFunction(formatted_raw_ostream &OS,
- DecoderSet &Decoders) const;
+ PredicateSet &Predicates, indent Indent) const;
+ void emitDecoderFunction(formatted_raw_ostream &OS, DecoderSet &Decoders,
+ StringRef SpecializedInsnType, indent Indent) const;
// run - Output the code emitter
void run(raw_ostream &o);
@@ -1059,38 +1076,53 @@ void DecoderEmitter::emitPredicateFunction(formatted_raw_ostream &OS,
}
void DecoderEmitter::emitDecoderFunction(formatted_raw_ostream &OS,
- DecoderSet &Decoders) const {
+ 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 << "template <typename InsnType>\n";
- OS << "DecodeStatus decodeFn" << Index << "(" << DecodeParams << ") {\n";
- OS << " " << TmpTypeDecl;
- OS << " [[maybe_unused]] TmpType tmp;\n";
+ emitTemplate();
+ OS << Indent << "DecodeStatus decodeFn" << Index << "(" << DecodeParams
+ << ") {\n";
+ Indent += 2;
+ OS << Indent << TmpTypeDecl;
+ OS << Indent << "[[maybe_unused]] TmpType tmp;\n";
OS << Decoder;
OS << " return S;\n";
OS << "}\n\n";
}
}
- OS << "// Handling " << Decoders.size() << " cases.\n";
- OS << "template <typename InsnType>\n";
- OS << "static DecodeStatus decodeToMCInst(unsigned Idx, " << DecodeParams
- << ") {\n";
- OS << " DecodeComplete = true;\n";
+ OS << Indent << "// Handling " << Decoders.size() << " cases.\n";
+ emitTemplate();
+ OS << Indent << "static DecodeStatus decodeToMCInst(unsigned Idx, "
+ << DecodeParams << ") {\n";
+ Indent += 2;
+ OS << Indent << "DecodeComplete = true;\n";
if (UseFnTableInDecodeToMCInst) {
// Build a table of function pointers.
@@ -2519,6 +2551,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);
@@ -2630,35 +2726,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, 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
@@ -2675,9 +2795,6 @@ namespace {
if (HasCheckPredicate)
emitPredicateFunction(OS, TableInfo.Predicates);
- // Emit the decoder function.
- emitDecoderFunction(OS, TableInfo.Decoders);
-
// Emit the main entry point for the decoder, decodeInstruction().
emitDecodeInstruction(OS, IsVarLenInst, OpcodeMask);
>From 60598a409dab9d21081b7e20e31c96783deaf4cd 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 02/12] 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 97b3755a28099..47329b2c2f4d2 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 d6072504f94f2..38970ef7a98df 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:
@@ -2550,66 +2544,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;
@@ -2732,12 +2723,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 52c9d34c566c70fb0b8c0f1e709278b05e633766 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 03/12] 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 38970ef7a98df..199a7420e883d 100644
--- a/llvm/utils/TableGen/DecoderEmitter.cpp
+++ b/llvm/utils/TableGen/DecoderEmitter.cpp
@@ -2246,7 +2246,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 =
@@ -2254,6 +2255,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++;
@@ -2262,11 +2271,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) {
@@ -2787,7 +2798,11 @@ namespace {
emitPredicateFunction(OS, TableInfo.Predicates);
// 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 71802ef8a5224c37f71d566e59ab70022b9d88b8 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 04/12] 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 04ec1716478e4..18605e0e0f37c 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPU.td
+++ b/llvm/lib/Target/AMDGPU/AMDGPU.td
@@ -2001,6 +2001,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 98f7e17e9528c..8a0c24555bddc 100644
--- a/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.cpp
+++ b/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.cpp
@@ -598,7 +598,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 199a7420e883d..c0374236bbbf4 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 {
@@ -1069,21 +1072,25 @@ 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";
+}
+
+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.
@@ -1092,14 +1099,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;
@@ -1112,7 +1119,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;
@@ -2184,12 +2191,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:
@@ -2197,35 +2211,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.
@@ -2240,11 +2302,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) {
@@ -2255,29 +2316,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) {
@@ -2481,16 +2532,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);
)";
}
@@ -2560,39 +2626,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.");
@@ -2603,7 +2666,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()) {
@@ -2633,9 +2696,7 @@ void DecoderEmitter::run(raw_ostream &o) {
namespace {
)";
- emitFieldFromInstruction(OS);
- emitInsertBits(OS);
- emitCheck(OS);
+ emitCommonFunctions(OS);
Target.reverseBitsForLittleEndianEncoding();
@@ -2685,7 +2746,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)) {
@@ -2728,6 +2789,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) {
@@ -2738,10 +2805,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;
@@ -2781,29 +2859,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);
- // 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 ae7d35129f7aa7d569ce55cc7906ba43b07ba969 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 05/12] 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 | 388 ++++++++----------
.../utils/TableGen/SearchableTableEmitter.cpp | 10 +-
12 files changed, 229 insertions(+), 312 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 18605e0e0f37c..4cf6ae364fb87 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPU.td
+++ b/llvm/lib/Target/AMDGPU/AMDGPU.td
@@ -2001,13 +2001,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 8a0c24555bddc..359f9fb4c1ac7 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;
@@ -497,26 +498,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,
@@ -599,7 +598,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,
@@ -634,7 +633,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 84041001b6ba7..6139a8679a2c0 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 c0374236bbbf4..155e05eedcdb6 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:
@@ -1060,13 +1049,13 @@ void DecoderEmitter::emitPredicateFunction(formatted_raw_ostream &OS,
PredicateSet &Predicates) const {
// The predicate function is just a big switch statement based on the
// input predicate index.
- OS << "static bool checkDecoderPredicate(unsigned Idx, const FeatureBitset "
- "&Bits) {\n";
+ OS << "static bool checkDecoderPredicate(unsigned Idx, "
+ << "const FeatureBitset &Bits) {\n";
OS << " switch (Idx) {\n";
- OS << " default: llvm_unreachable(\"Invalid index!\");\n";
+ OS << " default: llvm_unreachable(\"Invalid index!\");\n";
for (const auto &[Index, Predicate] : enumerate(Predicates)) {
- OS << " case " << Index << ":\n";
- OS << " return (" << Predicate << ");\n";
+ OS << " case " << Index << ":\n";
+ OS << " return (" << Predicate << ");\n";
}
OS << " }\n";
OS << "}\n\n";
@@ -1085,10 +1074,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
@@ -1098,51 +1086,53 @@ 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 << " 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 << " using DecodeFnTy = DecodeStatus (*)(" << DecodeParams << ");\n";
OS << " static constexpr DecodeFnTy decodeFnTable[] = {\n";
for (size_t Index : llvm::seq(Decoders.size()))
- OS << " decodeFn" << Index << ",\n";
+ 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, "
+ OS << "return decodeFnTable[Idx](S, insn, MI, Address, Decoder, "
"DecodeComplete);\n";
} else {
OS << " " << TmpTypeDecl;
OS << " TmpType tmp;\n";
OS << " switch (Idx) {\n";
- OS << " default: llvm_unreachable(\"Invalid index!\");\n";
+ OS << " default: llvm_unreachable(\"Invalid index!\");\n";
for (const auto &[Index, Decoder] : enumerate(Decoders)) {
- OS << " case " << Index << ":\n";
+ OS << " case " << Index << ":\n";
OS << Decoder;
OS << " return S;\n";
}
@@ -2191,24 +2181,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
@@ -2219,75 +2203,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);
}
-)",
- InsnType);
- } // if (GenerateTemplatedForm || !IsIntegralType)
- OS << "#undef DEC_EMIT_NO_INLINE\n";
+)";
+ } 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();
+}
+)";
+ }
+ 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.
@@ -2302,13 +2264,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 =
@@ -2318,24 +2281,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";
@@ -2459,19 +2423,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);
@@ -2482,18 +2447,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;
}
@@ -2504,7 +2469,8 @@ static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], MCInst &MI, )
// set before the decode attempt.
S = MCDisassembler::Success;
break;
- })";
+ })",
+ Suffix);
}
if (HasSoftFail) {
OS << R"(
@@ -2530,6 +2496,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) {
@@ -2621,64 +2600,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) {
@@ -2692,11 +2613,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();
@@ -2795,46 +2718,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.
@@ -2842,6 +2762,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!");
@@ -2857,13 +2778,50 @@ 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.
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 15db2ed4a6179543972f78b5617b053fe0dd45ff 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 06/12] 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 222652d3d70399f0338dc7a9fe2c0fbdcca059f3 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 07/12] 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 155e05eedcdb6..e22494c912d7a 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);
@@ -1061,56 +1074,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";
@@ -1127,8 +1191,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)) {
@@ -2183,27 +2247,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>
@@ -2218,19 +2289,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>
@@ -2245,7 +2309,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().
@@ -2269,8 +2360,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));
@@ -2279,26 +2369,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";
@@ -2712,16 +2793,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;
@@ -2729,17 +2812,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) {
@@ -2747,7 +2829,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.
@@ -2779,48 +2861,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);
}
}
>From 9f33a256b24d7fd21206e64b0fbe813e46907c5a Mon Sep 17 00:00:00 2001
From: Rahul Joshi <rjoshi at nvidia.com>
Date: Mon, 14 Jul 2025 12:19:11 -0700
Subject: [PATCH 08/12] Try fix clang-format
---
llvm/lib/TableGen/Record.cpp | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/llvm/lib/TableGen/Record.cpp b/llvm/lib/TableGen/Record.cpp
index 620928ef43dc5..1f3e5dc68f1d6 100644
--- a/llvm/lib/TableGen/Record.cpp
+++ b/llvm/lib/TableGen/Record.cpp
@@ -3140,10 +3140,10 @@ Record::getValueAsListOfStrings(StringRef FieldName) const {
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());
+ PrintFatalError(getLoc(),
+ Twine("Record `") + getName() + "', field `" + FieldName +
+ "' exists but does not have a list of strings value: " +
+ I->getAsString());
}
return Strings;
}
>From 357a409f1bb6e33705a686f0268e84d0b6f1a0d8 Mon Sep 17 00:00:00 2001
From: Rahul Joshi <rjoshi at nvidia.com>
Date: Mon, 14 Jul 2025 13:19:35 -0700
Subject: [PATCH 09/12] Review feedback
---
llvm/utils/TableGen/DecoderEmitter.cpp | 20 +++++++++-----------
1 file changed, 9 insertions(+), 11 deletions(-)
diff --git a/llvm/utils/TableGen/DecoderEmitter.cpp b/llvm/utils/TableGen/DecoderEmitter.cpp
index e22494c912d7a..1f17ce3c9fbff 100644
--- a/llvm/utils/TableGen/DecoderEmitter.cpp
+++ b/llvm/utils/TableGen/DecoderEmitter.cpp
@@ -1065,10 +1065,10 @@ void DecoderEmitter::emitPredicateFunction(formatted_raw_ostream &OS,
OS << "static bool checkDecoderPredicate(unsigned Idx, "
<< "const FeatureBitset &Bits) {\n";
OS << " switch (Idx) {\n";
- OS << " default: llvm_unreachable(\"Invalid index!\");\n";
+ OS << " default: llvm_unreachable(\"Invalid index!\");\n";
for (const auto &[Index, Predicate] : enumerate(Predicates)) {
- OS << " case " << Index << ":\n";
- OS << " return (" << Predicate << ");\n";
+ OS << " case " << Index << ":\n";
+ OS << " return (" << Predicate << ");\n";
}
OS << " }\n";
OS << "}\n\n";
@@ -1188,15 +1188,15 @@ void DecoderEmitter::emitDecoderFunction(formatted_raw_ostream &OS,
OS << " };\n";
OS << " if (Idx >= " << Decoders.size() << ")\n";
OS << " llvm_unreachable(\"Invalid index!\");\n";
- OS << "return decodeFnTable[Idx](S, insn, MI, Address, Decoder, "
+ OS << " return decodeFnTable[Idx](S, insn, MI, Address, Decoder, "
"DecodeComplete);\n";
} else {
emitTmpTypeDec();
OS << " " << TmpType << " tmp;\n";
OS << " switch (Idx) {\n";
- OS << " default: llvm_unreachable(\"Invalid index!\");\n";
+ OS << " default: llvm_unreachable(\"Invalid index!\");\n";
for (const auto &[Index, Decoder] : enumerate(Decoders)) {
- OS << " case " << Index << ":\n";
+ OS << " case " << Index << ":\n";
OS << Decoder;
OS << " return S;\n";
}
@@ -2302,16 +2302,13 @@ 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);
+ const std::bitset<N> Mask(maskTrailingOnes<uint64_t>(Size));
return ((Insn >> StartBit) & Mask).to_ullong();
}
)";
}
if (GenerateAPIntType) {
- // The templated version also works with APInt.
OS << R"(
static uint64_t fieldFromInstruction(const APInt &Insn, unsigned StartBit,
unsigned Size) {
@@ -2690,6 +2687,7 @@ void DecoderEmitter::run(raw_ostream &o) {
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/Support/DataTypes.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Support/MathExtras.h"
#include "llvm/Support/LEB128.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/TargetParser/SubtargetFeature.h"
@@ -2750,7 +2748,7 @@ namespace {
OpcMap;
std::map<unsigned, std::vector<OperandInfo>> Operands;
std::vector<unsigned> InstrLen;
- const bool IsVarLenInst = Target.hasVariableLengthEncodings();
+ bool IsVarLenInst = Target.hasVariableLengthEncodings();
unsigned MaxInstLen = 0;
for (const auto &[NEI, NumberedEncoding] : enumerate(NumberedEncodings)) {
>From e05e19aaab4af9854d6838bbb5f277292f2250f9 Mon Sep 17 00:00:00 2001
From: Rahul Joshi <rjoshi at nvidia.com>
Date: Mon, 14 Jul 2025 16:53:15 -0700
Subject: [PATCH 10/12] Flip default, fix build, and fix RISCV disassembler
---
llvm/include/llvm/Target/Target.td | 2 +-
llvm/lib/Target/AArch64/AArch64.td | 4 +---
llvm/lib/Target/AMDGPU/AMDGPU.td | 1 -
llvm/lib/Target/ARC/ARC.td | 5 ++++-
llvm/lib/Target/ARM/ARM.td | 4 +---
llvm/lib/Target/AVR/AVR.td | 5 ++++-
llvm/lib/Target/CSKY/CSKY.td | 5 ++++-
llvm/lib/Target/M68k/M68k.td | 4 +---
llvm/lib/Target/MSP430/MSP430.td | 5 ++++-
llvm/lib/Target/Mips/Mips.td | 2 ++
llvm/lib/Target/PowerPC/PPC.td | 2 ++
.../Target/RISCV/Disassembler/RISCVDisassembler.cpp | 13 +++++--------
llvm/lib/Target/SystemZ/SystemZ.td | 6 +++++-
llvm/lib/Target/Xtensa/Xtensa.td | 5 ++++-
llvm/utils/TableGen/DecoderEmitter.cpp | 2 +-
15 files changed, 39 insertions(+), 26 deletions(-)
diff --git a/llvm/include/llvm/Target/Target.td b/llvm/include/llvm/Target/Target.td
index 99f802b7b7251..431af4ff1a723 100644
--- a/llvm/include/llvm/Target/Target.td
+++ b/llvm/include/llvm/Target/Target.td
@@ -1162,7 +1162,7 @@ class InstrInfo {
// 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;
+ bit GenerateTemplatedDecoder = false;
}
// Standard Pseudo Instructions.
diff --git a/llvm/lib/Target/AArch64/AArch64.td b/llvm/lib/Target/AArch64/AArch64.td
index 5e1de716b6f79..86f95488e6bb7 100644
--- a/llvm/lib/Target/AArch64/AArch64.td
+++ b/llvm/lib/Target/AArch64/AArch64.td
@@ -40,9 +40,7 @@ include "AArch64SchedPredExynos.td"
include "AArch64SchedPredNeoverse.td"
include "AArch64Combine.td"
-def AArch64InstrInfo : InstrInfo {
- let GenerateTemplatedDecoder = false;
-}
+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 4cf6ae364fb87..04ec1716478e4 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPU.td
+++ b/llvm/lib/Target/AMDGPU/AMDGPU.td
@@ -2001,7 +2001,6 @@ def FeatureISAVersion12_Generic: FeatureSet<
def AMDGPUInstrInfo : InstrInfo {
let guessInstructionProperties = 1;
- let GenerateTemplatedDecoder = false;
}
def AMDGPUAsmParser : AsmParser {
diff --git a/llvm/lib/Target/ARC/ARC.td b/llvm/lib/Target/ARC/ARC.td
index 142ce7f747919..989dc53794ae6 100644
--- a/llvm/lib/Target/ARC/ARC.td
+++ b/llvm/lib/Target/ARC/ARC.td
@@ -24,7 +24,10 @@ include "ARCRegisterInfo.td"
include "ARCInstrInfo.td"
include "ARCCallingConv.td"
-def ARCInstrInfo : InstrInfo;
+def ARCInstrInfo : InstrInfo {
+ // FIXME: Migrate ARC disassembler to work with non-templated decoder.
+ let GenerateTemplatedDecoder = true;
+}
class Proc<string Name, list<SubtargetFeature> Features>
: Processor<Name, NoItineraries, Features>;
diff --git a/llvm/lib/Target/ARM/ARM.td b/llvm/lib/Target/ARM/ARM.td
index d21d5d988d19a..570aae9b3c7a7 100644
--- a/llvm/lib/Target/ARM/ARM.td
+++ b/llvm/lib/Target/ARM/ARM.td
@@ -38,9 +38,7 @@ include "ARMSchedule.td"
//===----------------------------------------------------------------------===//
include "ARMInstrInfo.td"
-def ARMInstrInfo : InstrInfo {
- let GenerateTemplatedDecoder = false;
-}
+def ARMInstrInfo : InstrInfo;
//===----------------------------------------------------------------------===//
// ARM schedules
diff --git a/llvm/lib/Target/AVR/AVR.td b/llvm/lib/Target/AVR/AVR.td
index 22ffc4a368ad6..dec1925b34035 100644
--- a/llvm/lib/Target/AVR/AVR.td
+++ b/llvm/lib/Target/AVR/AVR.td
@@ -32,7 +32,10 @@ include "AVRRegisterInfo.td"
include "AVRInstrInfo.td"
-def AVRInstrInfo : InstrInfo;
+def AVRInstrInfo : InstrInfo {
+ // FIXME: Migrate AVR disassembler to work with non-templated decoder.
+ let GenerateTemplatedDecoder = true;
+}
//===---------------------------------------------------------------------===//
// Calling Conventions
diff --git a/llvm/lib/Target/CSKY/CSKY.td b/llvm/lib/Target/CSKY/CSKY.td
index b5df93a9d464c..3d3d8dbe8bbfa 100644
--- a/llvm/lib/Target/CSKY/CSKY.td
+++ b/llvm/lib/Target/CSKY/CSKY.td
@@ -671,7 +671,10 @@ def : CK860V<"ck860fv", NoSchedModel,
// Define the CSKY target.
//===----------------------------------------------------------------------===//
-def CSKYInstrInfo : InstrInfo;
+def CSKYInstrInfo : InstrInfo {
+ // FIXME: Migrate CSKY disassembler to work with non-templated decoder.
+ let GenerateTemplatedDecoder = true;
+}
def CSKYAsmParser : AsmParser {
diff --git a/llvm/lib/Target/M68k/M68k.td b/llvm/lib/Target/M68k/M68k.td
index 0a8f0acd1c336..dab66d1022955 100644
--- a/llvm/lib/Target/M68k/M68k.td
+++ b/llvm/lib/Target/M68k/M68k.td
@@ -95,9 +95,7 @@ include "GISel/M68kRegisterBanks.td"
include "M68kInstrInfo.td"
-def M68kInstrInfo : InstrInfo {
- let GenerateTemplatedDecoder = false;
-}
+def M68kInstrInfo : InstrInfo;
//===----------------------------------------------------------------------===//
// Calling Conventions
diff --git a/llvm/lib/Target/MSP430/MSP430.td b/llvm/lib/Target/MSP430/MSP430.td
index 38aa30fcf4dd1..d6d569ce33204 100644
--- a/llvm/lib/Target/MSP430/MSP430.td
+++ b/llvm/lib/Target/MSP430/MSP430.td
@@ -61,7 +61,10 @@ include "MSP430CallingConv.td"
include "MSP430InstrInfo.td"
-def MSP430InstrInfo : InstrInfo;
+def MSP430InstrInfo : InstrInfo {
+ // FIXME: Migrate MPS430 disassembler to work with non-templated decoder.
+ let GenerateTemplatedDecoder = true;
+}
//===---------------------------------------------------------------------===//
// Assembly Printers
diff --git a/llvm/lib/Target/Mips/Mips.td b/llvm/lib/Target/Mips/Mips.td
index b346ba95f5984..49bec7e02e4b2 100644
--- a/llvm/lib/Target/Mips/Mips.td
+++ b/llvm/lib/Target/Mips/Mips.td
@@ -229,6 +229,8 @@ include "MipsScheduleP5600.td"
include "MipsScheduleGeneric.td"
def MipsInstrInfo : InstrInfo {
+ // FIXME: Migrate MIPS disassembler to work with non-templated decoder.
+ let GenerateTemplatedDecoder = true;
}
//===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/PowerPC/PPC.td b/llvm/lib/Target/PowerPC/PPC.td
index ea7c2203662bd..54b2ff6b3ef05 100644
--- a/llvm/lib/Target/PowerPC/PPC.td
+++ b/llvm/lib/Target/PowerPC/PPC.td
@@ -721,6 +721,8 @@ include "PPCCallingConv.td"
def PPCInstrInfo : InstrInfo {
let isLittleEndianEncoding = 1;
+ // FIXME: Migrate PPC disassembler to work with non-templated decoder.
+ let GenerateTemplatedDecoder = true;
}
def PPCAsmWriter : AsmWriter {
diff --git a/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
index b723958a6ff28..d4c28f07bf165 100644
--- a/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
+++ b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
@@ -815,9 +815,7 @@ DecodeStatus RISCVDisassembler::getInstruction32(MCInst &MI, uint64_t &Size,
}
Size = 4;
- // Use uint64_t to match getInstruction48. decodeInstruction is templated
- // on the Insn type.
- uint64_t Insn = support::endian::read32le(Bytes.data());
+ uint32_t Insn = support::endian::read32le(Bytes.data());
for (const DecoderListEntry &Entry : DecoderList32) {
if (!Entry.haveContainedFeatures(STI.getFeatureBits()))
@@ -863,9 +861,7 @@ DecodeStatus RISCVDisassembler::getInstruction16(MCInst &MI, uint64_t &Size,
}
Size = 2;
- // Use uint64_t to match getInstruction48. decodeInstruction is templated
- // on the Insn type.
- uint64_t Insn = support::endian::read16le(Bytes.data());
+ uint16_t Insn = support::endian::read16le(Bytes.data());
for (const DecoderListEntry &Entry : DecoderList16) {
if (!Entry.haveContainedFeatures(STI.getFeatureBits()))
@@ -899,9 +895,10 @@ DecodeStatus RISCVDisassembler::getInstruction48(MCInst &MI, uint64_t &Size,
}
Size = 6;
- uint64_t Insn = 0;
+ uint64_t InsnBits = 0;
for (size_t i = Size; i-- != 0;)
- Insn += (static_cast<uint64_t>(Bytes[i]) << 8 * i);
+ InsnBits += (static_cast<uint64_t>(Bytes[i]) << 8 * i);
+ std::bitset<48> Insn(InsnBits);
for (const DecoderListEntry &Entry : DecoderList48) {
if (!Entry.haveContainedFeatures(STI.getFeatureBits()))
diff --git a/llvm/lib/Target/SystemZ/SystemZ.td b/llvm/lib/Target/SystemZ/SystemZ.td
index ec110645c62dd..9961eee895326 100644
--- a/llvm/lib/Target/SystemZ/SystemZ.td
+++ b/llvm/lib/Target/SystemZ/SystemZ.td
@@ -57,7 +57,11 @@ include "SystemZInstrHFP.td"
include "SystemZInstrDFP.td"
include "SystemZInstrSystem.td"
-def SystemZInstrInfo : InstrInfo { let guessInstructionProperties = 0; }
+def SystemZInstrInfo : InstrInfo {
+ let guessInstructionProperties = 0;
+ // FIXME: Migrate SystemZ disassembler to work with non-templated decoder.
+ let GenerateTemplatedDecoder = true;
+}
//===----------------------------------------------------------------------===//
// Assembly parser
diff --git a/llvm/lib/Target/Xtensa/Xtensa.td b/llvm/lib/Target/Xtensa/Xtensa.td
index 2c4bacbe8282b..5fdaf3ad54942 100644
--- a/llvm/lib/Target/Xtensa/Xtensa.td
+++ b/llvm/lib/Target/Xtensa/Xtensa.td
@@ -46,7 +46,10 @@ include "XtensaCallingConv.td"
include "XtensaInstrInfo.td"
-def XtensaInstrInfo : InstrInfo;
+def XtensaInstrInfo : InstrInfo {
+ // FIXME: Migrate XTensa disassembler to work with non-templated decoder.
+ let GenerateTemplatedDecoder = true;
+}
//===----------------------------------------------------------------------===//
// Target Declaration
diff --git a/llvm/utils/TableGen/DecoderEmitter.cpp b/llvm/utils/TableGen/DecoderEmitter.cpp
index 1f17ce3c9fbff..e3506a38aceee 100644
--- a/llvm/utils/TableGen/DecoderEmitter.cpp
+++ b/llvm/utils/TableGen/DecoderEmitter.cpp
@@ -2854,7 +2854,7 @@ namespace {
TableInfo.Table.push_back(MCD::OPC_Fail);
// Print the table to the output stream.
- OpcodeMask |= emitTable(OS, TableInfo.Table, indent(0), FC.getBitWidth(),
+ OpcodeMask |= emitTable(OS, TableInfo.Table, FC.getBitWidth(),
DecoderNamespace, EncodingIDs);
}
>From 640c99aeabaf01dfed8cdb22dbec7cfd25b2c558 Mon Sep 17 00:00:00 2001
From: Rahul Joshi <rjoshi at nvidia.com>
Date: Mon, 14 Jul 2025 16:59:41 -0700
Subject: [PATCH 11/12] Delete unused header added in earlier version
---
llvm/utils/TableGen/DecoderEmitter.cpp | 1 -
1 file changed, 1 deletion(-)
diff --git a/llvm/utils/TableGen/DecoderEmitter.cpp b/llvm/utils/TableGen/DecoderEmitter.cpp
index e3506a38aceee..16c0c65943556 100644
--- a/llvm/utils/TableGen/DecoderEmitter.cpp
+++ b/llvm/utils/TableGen/DecoderEmitter.cpp
@@ -15,7 +15,6 @@
#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"
>From 6bb22bfb95aabd57f2e14b2eaf308fc2ef670b32 Mon Sep 17 00:00:00 2001
From: Rahul Joshi <rjoshi at nvidia.com>
Date: Tue, 15 Jul 2025 06:50:09 -0700
Subject: [PATCH 12/12] Fix test cases, review feedback
---
llvm/test/TableGen/DecoderEmitterFnTable.td | 10 +++---
llvm/test/TableGen/HwModeEncodeDecode3.td | 19 +++++++----
llvm/utils/TableGen/DecoderEmitter.cpp | 37 ++++++++++-----------
3 files changed, 35 insertions(+), 31 deletions(-)
diff --git a/llvm/test/TableGen/DecoderEmitterFnTable.td b/llvm/test/TableGen/DecoderEmitterFnTable.td
index ebef1cf3c10c9..f7e28dc16ef1c 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 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-LABEL: DecodeStatus decodeFn_0(DecodeStatus S, uint8_t insn, MCInst &MI, uint64_t Address, const MCDisassembler *Decoder, bool &DecodeComplete)
+// CHECK-LABEL: DecodeStatus decodeFn_1(DecodeStatus S, uint8_t insn, MCInst &MI, uint64_t Address, const MCDisassembler *Decoder, bool &DecodeComplete)
+// CHECK-LABEL: DecodeStatus decodeFn_2(DecodeStatus S, uint8_t insn, MCInst &MI, uint64_t Address, const MCDisassembler *Decoder, bool &DecodeComplete)
+// CHECK-LABEL: DecodeStatus decodeFn_3(DecodeStatus S, uint8_t insn, MCInst &MI, uint64_t Address, const MCDisassembler *Decoder, bool &DecodeComplete)
+// CHECK-LABEL: decodeToMCInst(unsigned Idx, DecodeStatus S, uint8_t insn, MCInst &MI, uint64_t Address, const MCDisassembler *Decoder, bool &DecodeComplete)
// CHECK: static constexpr DecodeFnTy decodeFnTable[]
// CHECK-NEXT: decodeFn_0,
// CHECK-NEXT: decodeFn_1,
diff --git a/llvm/test/TableGen/HwModeEncodeDecode3.td b/llvm/test/TableGen/HwModeEncodeDecode3.td
index c4d488d9d5f8f..d9172b0384e8c 100644
--- a/llvm/test/TableGen/HwModeEncodeDecode3.td
+++ b/llvm/test/TableGen/HwModeEncodeDecode3.td
@@ -118,8 +118,6 @@ def unrelated: Instruction {
// exact duplicates and could effectively be merged into one.
// DECODER-LABEL: DecoderTable32[] =
// DECODER-DAG: Opcode: bar
-// DECODER-LABEL: DecoderTable64[] =
-// DECODER-DAG: Opcode: fooTypeEncDefault:foo
// DECODER-LABEL: DecoderTableAlt32[] =
// DECODER-DAG: Opcode: unrelated
// DECODER-LABEL: DecoderTableAlt_ModeA32[] =
@@ -138,13 +136,13 @@ def unrelated: Instruction {
// DECODER-LABEL: DecoderTable_ModeC32[] =
// DECODER-DAG: Opcode: fooTypeEncC:foo
// DECODER-DAG: Opcode: bar
+// DECODER-LABEL: DecoderTable64[] =
+// DECODER-DAG: Opcode: fooTypeEncDefault:foo
// Under the 'O1' optimization level, unnecessary duplicate tables will be eliminated,
// reducing the four ‘Alt’ tables down to just one.
// DECODER-SUPPRESS-O1-LABEL: DecoderTable32[] =
// DECODER-SUPPRESS-O1-DAG: Opcode: bar
-// DECODER-SUPPRESS-O1-LABEL: DecoderTable64[] =
-// DECODER-SUPPRESS-O1-DAG: Opcode: fooTypeEncDefault:foo
// DECODER-SUPPRESS-O1-LABEL: DecoderTableAlt32[] =
// DECODER-SUPPRESS-O1-DAG: Opcode: unrelated
// DECODER-SUPPRESS-O1-LABEL: DecoderTable_ModeA32[] =
@@ -157,6 +155,8 @@ def unrelated: Instruction {
// DECODER-SUPPRESS-O1-LABEL: DecoderTable_ModeC32[] =
// DECODER-SUPPRESS-O1-DAG: Opcode: fooTypeEncC:foo
// DECODER-SUPPRESS-O1-DAG: Opcode: bar
+// DECODER-SUPPRESS-O1-LABEL: DecoderTable64[] =
+// DECODER-SUPPRESS-O1-DAG: Opcode: fooTypeEncDefault:foo
// Under the 'O2' optimization condition, instructions possessing the 'EncodingByHwMode'
// attribute will be extracted from their original DecoderNamespace and placed into their
@@ -164,11 +164,13 @@ def unrelated: Instruction {
// attribute but are within the same DecoderNamespace will be stored in the 'Default' table. This
// approach will significantly reduce instruction redundancy, but it necessitates users to thoroughly
// consider the interplay between HwMode and DecoderNamespace for their instructions.
+//
+// Additionally, no 32-bit instruction will appear in a 64-bit decoder table and
+// vice-versa.
+//
// DECODER-SUPPRESS-O2-LABEL: DecoderTable32[] =
// DECODER-SUPPRESS-O2-DAG: Opcode: bar
-// DECODER-SUPPRESS-O2-LABEL: DecoderTable64[] =
-// DECODER-SUPPRESS-O2-NOT: Opcode: bar
-// DECODER-SUPPRESS-O2-DAG: Opcode: fooTypeEncDefault:foo
+// DECODER-SUPPRESS-O2-NOT: Opcode: fooTypeEncDefault:foo
// DECODER-SUPPRESS-O2-LABEL: DecoderTableAlt32[] =
// DECODER-SUPPRESS-O2-DAG: Opcode: unrelated
// DECODER-SUPPRESS-O2-LABEL: DecoderTable_ModeA32[] =
@@ -181,6 +183,9 @@ def unrelated: Instruction {
// DECODER-SUPPRESS-O2-LABEL: DecoderTable_ModeC32[] =
// DECODER-SUPPRESS-O2-DAG: Opcode: fooTypeEncC:foo
// DECODER-SUPPRESS-O2-NOT: Opcode: bar
+// DECODER-SUPPRESS-O2-LABEL: DecoderTable64[] =
+// DECODER-SUPPRESS-O2-DAG: Opcode: fooTypeEncDefault:foo
+// DECODER-SUPPRESS-O2-NOT: Opcode: bar
// For 'bar' and 'unrelated', we didn't assign any HwModes for them,
// they should keep the same in the following four tables.
diff --git a/llvm/utils/TableGen/DecoderEmitter.cpp b/llvm/utils/TableGen/DecoderEmitter.cpp
index 16c0c65943556..0bfc8b479bec9 100644
--- a/llvm/utils/TableGen/DecoderEmitter.cpp
+++ b/llvm/utils/TableGen/DecoderEmitter.cpp
@@ -2244,8 +2244,7 @@ populateInstruction(const CodeGenTarget &Target, const Record &EncodingDef,
return Bits.getNumBits();
}
-// emitFieldFromInstruction - Emit the templated helper function
-// fieldFromInstruction().
+// 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
@@ -2298,10 +2297,10 @@ fieldFromInstruction(const IntType &Insn, unsigned StartBit, unsigned Size) {
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!");
- const std::bitset<N> Mask(maskTrailingOnes<uint64_t>(Size));
+ unsigned NumBits) {
+ assert(StartBit + NumBits <= N && "Instruction field out of bounds!");
+ assert(NumBits <= 64 && "Cannot support >64-bit extractions!");
+ const std::bitset<N> Mask(maskTrailingOnes<uint64_t>(NumBits));
return ((Insn >> StartBit) & Mask).to_ullong();
}
)";
@@ -2310,8 +2309,8 @@ uint64_t fieldFromInstruction(const std::bitset<N>& Insn, unsigned StartBit,
if (GenerateAPIntType) {
OS << R"(
static uint64_t fieldFromInstruction(const APInt &Insn, unsigned StartBit,
- unsigned Size) {
- return Insn.extractBitsAsZExtValue(Size, StartBit);
+ unsigned NumBits) {
+ return Insn.extractBitsAsZExtValue(NumBits, StartBit);
}
)";
}
@@ -2321,40 +2320,40 @@ static uint64_t fieldFromInstruction(const APInt &Insn, unsigned StartBit,
// 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 extractBitsAsZExtValue(NumBits, 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);
+ unsigned NumBits) {
+ return Insn.extractBitsAsZExtValue(NumBits, StartBit);
}
)";
}
}
-// emitInsertBits - Emit the helper function insertBits().
+// 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.
template <typename IntType>
static std::enable_if_t<std::is_integral_v<IntType>, void>
-insertBits(IntType &field, IntType bits, unsigned startBit, unsigned numBits) {
+insertBits(IntType &Field, IntType Bits, unsigned StartBit, unsigned NumBits) {
// Check that no bit beyond numBits is set, so that a simple bitwise |
// is sufficient.
- assert((~(((IntType)1 << numBits) - 1) & bits) == 0 &&
- "bits has more than numBits bits set");
- assert(startBit + numBits <= sizeof(IntType) * 8);
+ assert((~(((IntType)1 << NumBits) - 1) & Bits) == 0 &&
+ "Bits has more than NumBits bits set");
+ assert(StartBit + NumBits <= sizeof(IntType) * 8);
(void)numBits;
- field |= bits << startBit;
+ Field |= Bits << StartBit;
}
)";
}
-// emitDecodeInstruction - Emit the entry function function decodeInstruction().
+// Emit the entry function function decodeInstruction().
static void emitDecodeInstruction(formatted_raw_ostream &OS, bool IsVarLenInst,
unsigned OpcodeMask, const CPPType &Type,
StringRef Suffix) {
@@ -2790,7 +2789,7 @@ namespace {
}
}
- const bool GenerateTemplated =
+ bool GenerateTemplated =
Target.getInstructionSet()->getValueAsBit("GenerateTemplatedDecoder");
// For variable instruction, we emit a instruction length table to let the
More information about the llvm-commits
mailing list