From ae24279533736da279301a884a926b906778bd21 Mon Sep 17 00:00:00 2001 From: Rahul Joshi Date: Tue, 1 Jul 2025 09:47:10 -0700 Subject: [PATCH 1/5] [TableGen][DecoderEmitter] Add option to emit type-specialized `decodeToMCInst` --- llvm/lib/Target/AArch64/CMakeLists.txt | 3 +- llvm/lib/Target/AMDGPU/CMakeLists.txt | 5 +- llvm/lib/Target/ARC/CMakeLists.txt | 4 +- llvm/lib/Target/ARM/CMakeLists.txt | 4 +- llvm/lib/Target/AVR/CMakeLists.txt | 3 +- llvm/lib/Target/BPF/CMakeLists.txt | 3 +- llvm/lib/Target/CSKY/CMakeLists.txt | 3 +- llvm/lib/Target/Hexagon/CMakeLists.txt | 3 +- llvm/lib/Target/Lanai/CMakeLists.txt | 3 +- llvm/lib/Target/LoongArch/CMakeLists.txt | 3 +- llvm/lib/Target/MSP430/CMakeLists.txt | 3 +- llvm/lib/Target/Mips/CMakeLists.txt | 3 +- llvm/lib/Target/PowerPC/CMakeLists.txt | 3 +- llvm/lib/Target/RISCV/CMakeLists.txt | 4 +- llvm/lib/Target/Sparc/CMakeLists.txt | 3 +- llvm/lib/Target/SystemZ/CMakeLists.txt | 3 +- llvm/lib/Target/VE/CMakeLists.txt | 3 +- llvm/lib/Target/XCore/CMakeLists.txt | 4 +- llvm/lib/Target/Xtensa/CMakeLists.txt | 3 +- llvm/test/TableGen/VarLenDecoder.td | 13 +- llvm/utils/TableGen/DecoderEmitter.cpp | 187 ++++++++++++++++++----- 21 files changed, 202 insertions(+), 61 deletions(-) diff --git a/llvm/lib/Target/AArch64/CMakeLists.txt b/llvm/lib/Target/AArch64/CMakeLists.txt index 66136a464f05d..98cc8693144f0 100644 --- a/llvm/lib/Target/AArch64/CMakeLists.txt +++ b/llvm/lib/Target/AArch64/CMakeLists.txt @@ -7,7 +7,8 @@ tablegen(LLVM AArch64GenAsmWriter.inc -gen-asm-writer) tablegen(LLVM AArch64GenAsmWriter1.inc -gen-asm-writer -asmwriternum=1) tablegen(LLVM AArch64GenCallingConv.inc -gen-callingconv) tablegen(LLVM AArch64GenDAGISel.inc -gen-dag-isel) -tablegen(LLVM AArch64GenDisassemblerTables.inc -gen-disassembler) +tablegen(LLVM AArch64GenDisassemblerTables.inc -gen-disassembler + -non-templated-decode-to-mcinst-type-spec=uint32_t:=32) tablegen(LLVM AArch64GenFastISel.inc -gen-fast-isel) tablegen(LLVM AArch64GenGlobalISel.inc -gen-global-isel) tablegen(LLVM AArch64GenO0PreLegalizeGICombiner.inc -gen-global-isel-combiner diff --git a/llvm/lib/Target/AMDGPU/CMakeLists.txt b/llvm/lib/Target/AMDGPU/CMakeLists.txt index e3519f192137c..6254750c10c3c 100644 --- a/llvm/lib/Target/AMDGPU/CMakeLists.txt +++ b/llvm/lib/Target/AMDGPU/CMakeLists.txt @@ -6,7 +6,10 @@ tablegen(LLVM AMDGPUGenAsmMatcher.inc -gen-asm-matcher) tablegen(LLVM AMDGPUGenAsmWriter.inc -gen-asm-writer) tablegen(LLVM AMDGPUGenCallingConv.inc -gen-callingconv) tablegen(LLVM AMDGPUGenDAGISel.inc -gen-dag-isel) -tablegen(LLVM AMDGPUGenDisassemblerTables.inc -gen-disassembler) +tablegen(LLVM AMDGPUGenDisassemblerTables.inc -gen-disassembler + -non-templated-decode-to-mcinst-type-spec=uint32_t:=32 + -non-templated-decode-to-mcinst-type-spec=uint64_t:=64 + -non-templated-decode-to-mcinst-type-spec=DecoderUInt128:=96,128) tablegen(LLVM AMDGPUGenInstrInfo.inc -gen-instr-info) tablegen(LLVM AMDGPUGenMCCodeEmitter.inc -gen-emitter) tablegen(LLVM AMDGPUGenMCPseudoLowering.inc -gen-pseudo-lowering) diff --git a/llvm/lib/Target/ARC/CMakeLists.txt b/llvm/lib/Target/ARC/CMakeLists.txt index 196cc31cc5080..e6656576fbcc3 100644 --- a/llvm/lib/Target/ARC/CMakeLists.txt +++ b/llvm/lib/Target/ARC/CMakeLists.txt @@ -5,7 +5,9 @@ set(LLVM_TARGET_DEFINITIONS ARC.td) tablegen(LLVM ARCGenAsmWriter.inc -gen-asm-writer) tablegen(LLVM ARCGenCallingConv.inc -gen-callingconv) tablegen(LLVM ARCGenDAGISel.inc -gen-dag-isel) -tablegen(LLVM ARCGenDisassemblerTables.inc -gen-disassembler) +tablegen(LLVM ARCGenDisassemblerTables.inc -gen-disassembler + -non-templated-decode-to-mcinst-type-spec=uint32_t:=16,32 + -non-templated-decode-to-mcinst-type-spec=uint64_t:=48,64) tablegen(LLVM ARCGenInstrInfo.inc -gen-instr-info) tablegen(LLVM ARCGenRegisterInfo.inc -gen-register-info) tablegen(LLVM ARCGenSDNodeInfo.inc -gen-sd-node-info) diff --git a/llvm/lib/Target/ARM/CMakeLists.txt b/llvm/lib/Target/ARM/CMakeLists.txt index a39629bd8aeb0..718a084ec6388 100644 --- a/llvm/lib/Target/ARM/CMakeLists.txt +++ b/llvm/lib/Target/ARM/CMakeLists.txt @@ -6,7 +6,9 @@ tablegen(LLVM ARMGenAsmMatcher.inc -gen-asm-matcher) tablegen(LLVM ARMGenAsmWriter.inc -gen-asm-writer) tablegen(LLVM ARMGenCallingConv.inc -gen-callingconv) tablegen(LLVM ARMGenDAGISel.inc -gen-dag-isel) -tablegen(LLVM ARMGenDisassemblerTables.inc -gen-disassembler) +tablegen(LLVM ARMGenDisassemblerTables.inc -gen-disassembler + -non-templated-decode-to-mcinst-type-spec=uint16_t:=16 + -non-templated-decode-to-mcinst-type-spec=uint32_t:=32) tablegen(LLVM ARMGenFastISel.inc -gen-fast-isel) tablegen(LLVM ARMGenGlobalISel.inc -gen-global-isel) tablegen(LLVM ARMGenInstrInfo.inc -gen-instr-info) diff --git a/llvm/lib/Target/AVR/CMakeLists.txt b/llvm/lib/Target/AVR/CMakeLists.txt index 781dac02c7083..a2da85d77a325 100644 --- a/llvm/lib/Target/AVR/CMakeLists.txt +++ b/llvm/lib/Target/AVR/CMakeLists.txt @@ -6,7 +6,8 @@ tablegen(LLVM AVRGenAsmMatcher.inc -gen-asm-matcher) tablegen(LLVM AVRGenAsmWriter.inc -gen-asm-writer) tablegen(LLVM AVRGenCallingConv.inc -gen-callingconv) tablegen(LLVM AVRGenDAGISel.inc -gen-dag-isel) -tablegen(LLVM AVRGenDisassemblerTables.inc -gen-disassembler) +tablegen(LLVM AVRGenDisassemblerTables.inc -gen-disassembler + -non-templated-decode-to-mcinst-type-spec=uint32_t:=16,32) tablegen(LLVM AVRGenInstrInfo.inc -gen-instr-info) tablegen(LLVM AVRGenMCCodeEmitter.inc -gen-emitter) tablegen(LLVM AVRGenRegisterInfo.inc -gen-register-info) diff --git a/llvm/lib/Target/BPF/CMakeLists.txt b/llvm/lib/Target/BPF/CMakeLists.txt index eade4cacb7100..6a609d645dfa1 100644 --- a/llvm/lib/Target/BPF/CMakeLists.txt +++ b/llvm/lib/Target/BPF/CMakeLists.txt @@ -6,7 +6,8 @@ tablegen(LLVM BPFGenAsmMatcher.inc -gen-asm-matcher) tablegen(LLVM BPFGenAsmWriter.inc -gen-asm-writer) tablegen(LLVM BPFGenCallingConv.inc -gen-callingconv) tablegen(LLVM BPFGenDAGISel.inc -gen-dag-isel) -tablegen(LLVM BPFGenDisassemblerTables.inc -gen-disassembler) +tablegen(LLVM BPFGenDisassemblerTables.inc -gen-disassembler + -non-templated-decode-to-mcinst-type-spec=uint64_t:=64) tablegen(LLVM BPFGenInstrInfo.inc -gen-instr-info) tablegen(LLVM BPFGenMCCodeEmitter.inc -gen-emitter) tablegen(LLVM BPFGenRegisterInfo.inc -gen-register-info) diff --git a/llvm/lib/Target/CSKY/CMakeLists.txt b/llvm/lib/Target/CSKY/CMakeLists.txt index 4b900bc99c271..eadf0169edef1 100644 --- a/llvm/lib/Target/CSKY/CMakeLists.txt +++ b/llvm/lib/Target/CSKY/CMakeLists.txt @@ -7,7 +7,8 @@ tablegen(LLVM CSKYGenAsmWriter.inc -gen-asm-writer) tablegen(LLVM CSKYGenCallingConv.inc -gen-callingconv) tablegen(LLVM CSKYGenCompressInstEmitter.inc -gen-compress-inst-emitter) tablegen(LLVM CSKYGenDAGISel.inc -gen-dag-isel) -tablegen(LLVM CSKYGenDisassemblerTables.inc -gen-disassembler) +tablegen(LLVM CSKYGenDisassemblerTables.inc -gen-disassembler + -non-templated-decode-to-mcinst-type-spec=uint32_t:=16,32) tablegen(LLVM CSKYGenInstrInfo.inc -gen-instr-info) tablegen(LLVM CSKYGenMCCodeEmitter.inc -gen-emitter) tablegen(LLVM CSKYGenMCPseudoLowering.inc -gen-pseudo-lowering) diff --git a/llvm/lib/Target/Hexagon/CMakeLists.txt b/llvm/lib/Target/Hexagon/CMakeLists.txt index d758260a8ab5d..be2bc89155612 100644 --- a/llvm/lib/Target/Hexagon/CMakeLists.txt +++ b/llvm/lib/Target/Hexagon/CMakeLists.txt @@ -7,7 +7,8 @@ tablegen(LLVM HexagonGenAsmWriter.inc -gen-asm-writer) tablegen(LLVM HexagonGenCallingConv.inc -gen-callingconv) tablegen(LLVM HexagonGenDAGISel.inc -gen-dag-isel) tablegen(LLVM HexagonGenDFAPacketizer.inc -gen-dfa-packetizer) -tablegen(LLVM HexagonGenDisassemblerTables.inc -gen-disassembler) +tablegen(LLVM HexagonGenDisassemblerTables.inc -gen-disassembler + -non-templated-decode-to-mcinst-type-spec=uint32_t:=32) tablegen(LLVM HexagonGenInstrInfo.inc -gen-instr-info) tablegen(LLVM HexagonGenMCCodeEmitter.inc -gen-emitter) tablegen(LLVM HexagonGenRegisterInfo.inc -gen-register-info) diff --git a/llvm/lib/Target/Lanai/CMakeLists.txt b/llvm/lib/Target/Lanai/CMakeLists.txt index 4a628e13fc177..dfb0c93e1a5e3 100644 --- a/llvm/lib/Target/Lanai/CMakeLists.txt +++ b/llvm/lib/Target/Lanai/CMakeLists.txt @@ -6,7 +6,8 @@ tablegen(LLVM LanaiGenAsmMatcher.inc -gen-asm-matcher) tablegen(LLVM LanaiGenAsmWriter.inc -gen-asm-writer) tablegen(LLVM LanaiGenCallingConv.inc -gen-callingconv) tablegen(LLVM LanaiGenDAGISel.inc -gen-dag-isel) -tablegen(LLVM LanaiGenDisassemblerTables.inc -gen-disassembler) +tablegen(LLVM LanaiGenDisassemblerTables.inc -gen-disassembler + -non-templated-decode-to-mcinst-type-spec=uint32_t:=32) tablegen(LLVM LanaiGenInstrInfo.inc -gen-instr-info) tablegen(LLVM LanaiGenMCCodeEmitter.inc -gen-emitter) tablegen(LLVM LanaiGenRegisterInfo.inc -gen-register-info) diff --git a/llvm/lib/Target/LoongArch/CMakeLists.txt b/llvm/lib/Target/LoongArch/CMakeLists.txt index 0f674b1b0fa9e..c851f5c2fc1da 100644 --- a/llvm/lib/Target/LoongArch/CMakeLists.txt +++ b/llvm/lib/Target/LoongArch/CMakeLists.txt @@ -5,7 +5,8 @@ set(LLVM_TARGET_DEFINITIONS LoongArch.td) tablegen(LLVM LoongArchGenAsmMatcher.inc -gen-asm-matcher) tablegen(LLVM LoongArchGenAsmWriter.inc -gen-asm-writer) tablegen(LLVM LoongArchGenDAGISel.inc -gen-dag-isel) -tablegen(LLVM LoongArchGenDisassemblerTables.inc -gen-disassembler) +tablegen(LLVM LoongArchGenDisassemblerTables.inc -gen-disassembler + -non-templated-decode-to-mcinst-type-spec=uint32_t:=32) tablegen(LLVM LoongArchGenInstrInfo.inc -gen-instr-info) tablegen(LLVM LoongArchGenMCPseudoLowering.inc -gen-pseudo-lowering) tablegen(LLVM LoongArchGenMCCodeEmitter.inc -gen-emitter) diff --git a/llvm/lib/Target/MSP430/CMakeLists.txt b/llvm/lib/Target/MSP430/CMakeLists.txt index 4081d3472fd78..f10c8192e7df0 100644 --- a/llvm/lib/Target/MSP430/CMakeLists.txt +++ b/llvm/lib/Target/MSP430/CMakeLists.txt @@ -6,7 +6,8 @@ tablegen(LLVM MSP430GenAsmMatcher.inc -gen-asm-matcher) tablegen(LLVM MSP430GenAsmWriter.inc -gen-asm-writer) tablegen(LLVM MSP430GenCallingConv.inc -gen-callingconv) tablegen(LLVM MSP430GenDAGISel.inc -gen-dag-isel) -tablegen(LLVM MSP430GenDisassemblerTables.inc -gen-disassembler) +tablegen(LLVM MSP430GenDisassemblerTables.inc -gen-disassembler + -non-templated-decode-to-mcinst-type-spec=uint64_t:=16,32,48) tablegen(LLVM MSP430GenInstrInfo.inc -gen-instr-info) tablegen(LLVM MSP430GenMCCodeEmitter.inc -gen-emitter) tablegen(LLVM MSP430GenRegisterInfo.inc -gen-register-info) diff --git a/llvm/lib/Target/Mips/CMakeLists.txt b/llvm/lib/Target/Mips/CMakeLists.txt index 21d1765107ae6..2516d00706a91 100644 --- a/llvm/lib/Target/Mips/CMakeLists.txt +++ b/llvm/lib/Target/Mips/CMakeLists.txt @@ -6,7 +6,8 @@ tablegen(LLVM MipsGenAsmMatcher.inc -gen-asm-matcher) tablegen(LLVM MipsGenAsmWriter.inc -gen-asm-writer) tablegen(LLVM MipsGenCallingConv.inc -gen-callingconv) tablegen(LLVM MipsGenDAGISel.inc -gen-dag-isel) -tablegen(LLVM MipsGenDisassemblerTables.inc -gen-disassembler) +tablegen(LLVM MipsGenDisassemblerTables.inc -gen-disassembler + -non-templated-decode-to-mcinst-type-spec=uint32_t:=16,32) tablegen(LLVM MipsGenFastISel.inc -gen-fast-isel) tablegen(LLVM MipsGenGlobalISel.inc -gen-global-isel) tablegen(LLVM MipsGenPostLegalizeGICombiner.inc -gen-global-isel-combiner diff --git a/llvm/lib/Target/PowerPC/CMakeLists.txt b/llvm/lib/Target/PowerPC/CMakeLists.txt index 3808a26a0b92a..136db0634eb93 100644 --- a/llvm/lib/Target/PowerPC/CMakeLists.txt +++ b/llvm/lib/Target/PowerPC/CMakeLists.txt @@ -6,7 +6,8 @@ tablegen(LLVM PPCGenAsmMatcher.inc -gen-asm-matcher) tablegen(LLVM PPCGenAsmWriter.inc -gen-asm-writer) tablegen(LLVM PPCGenCallingConv.inc -gen-callingconv) tablegen(LLVM PPCGenDAGISel.inc -gen-dag-isel) -tablegen(LLVM PPCGenDisassemblerTables.inc -gen-disassembler) +tablegen(LLVM PPCGenDisassemblerTables.inc -gen-disassembler + -non-templated-decode-to-mcinst-type-spec=uint64_t:=32,64) tablegen(LLVM PPCGenFastISel.inc -gen-fast-isel) tablegen(LLVM PPCGenInstrInfo.inc -gen-instr-info) tablegen(LLVM PPCGenMCCodeEmitter.inc -gen-emitter) diff --git a/llvm/lib/Target/RISCV/CMakeLists.txt b/llvm/lib/Target/RISCV/CMakeLists.txt index e32d6eab3b977..9df6701387d43 100644 --- a/llvm/lib/Target/RISCV/CMakeLists.txt +++ b/llvm/lib/Target/RISCV/CMakeLists.txt @@ -7,7 +7,9 @@ tablegen(LLVM RISCVGenAsmWriter.inc -gen-asm-writer) tablegen(LLVM RISCVGenCompressInstEmitter.inc -gen-compress-inst-emitter) tablegen(LLVM RISCVGenMacroFusion.inc -gen-macro-fusion-pred) tablegen(LLVM RISCVGenDAGISel.inc -gen-dag-isel) -tablegen(LLVM RISCVGenDisassemblerTables.inc -gen-disassembler) +tablegen(LLVM RISCVGenDisassemblerTables.inc -gen-disassembler + -non-templated-decode-to-mcinst-type-spec=uint32_t:=16,32 + -non-templated-decode-to-mcinst-type-spec=uint64_t:=48) tablegen(LLVM RISCVGenInstrInfo.inc -gen-instr-info) tablegen(LLVM RISCVGenMCCodeEmitter.inc -gen-emitter) tablegen(LLVM RISCVGenMCPseudoLowering.inc -gen-pseudo-lowering) diff --git a/llvm/lib/Target/Sparc/CMakeLists.txt b/llvm/lib/Target/Sparc/CMakeLists.txt index f682719ac483f..6334dbbc6cc1a 100644 --- a/llvm/lib/Target/Sparc/CMakeLists.txt +++ b/llvm/lib/Target/Sparc/CMakeLists.txt @@ -6,7 +6,8 @@ tablegen(LLVM SparcGenAsmMatcher.inc -gen-asm-matcher) tablegen(LLVM SparcGenAsmWriter.inc -gen-asm-writer) tablegen(LLVM SparcGenCallingConv.inc -gen-callingconv) tablegen(LLVM SparcGenDAGISel.inc -gen-dag-isel) -tablegen(LLVM SparcGenDisassemblerTables.inc -gen-disassembler) +tablegen(LLVM SparcGenDisassemblerTables.inc -gen-disassembler + -non-templated-decode-to-mcinst-type-spec=uint32_t:=32) tablegen(LLVM SparcGenInstrInfo.inc -gen-instr-info) tablegen(LLVM SparcGenMCCodeEmitter.inc -gen-emitter) tablegen(LLVM SparcGenRegisterInfo.inc -gen-register-info) diff --git a/llvm/lib/Target/SystemZ/CMakeLists.txt b/llvm/lib/Target/SystemZ/CMakeLists.txt index 0d8f3eac6ee4f..1caeef468f3fb 100644 --- a/llvm/lib/Target/SystemZ/CMakeLists.txt +++ b/llvm/lib/Target/SystemZ/CMakeLists.txt @@ -7,7 +7,8 @@ tablegen(LLVM SystemZGenGNUAsmWriter.inc -gen-asm-writer) tablegen(LLVM SystemZGenHLASMAsmWriter.inc -gen-asm-writer -asmwriternum=1) tablegen(LLVM SystemZGenCallingConv.inc -gen-callingconv) tablegen(LLVM SystemZGenDAGISel.inc -gen-dag-isel) -tablegen(LLVM SystemZGenDisassemblerTables.inc -gen-disassembler) +tablegen(LLVM SystemZGenDisassemblerTables.inc -gen-disassembler + -non-templated-decode-to-mcinst-type-spec=uint64_t:=16,32,48) tablegen(LLVM SystemZGenInstrInfo.inc -gen-instr-info) tablegen(LLVM SystemZGenMCCodeEmitter.inc -gen-emitter) tablegen(LLVM SystemZGenRegisterInfo.inc -gen-register-info) diff --git a/llvm/lib/Target/VE/CMakeLists.txt b/llvm/lib/Target/VE/CMakeLists.txt index d1bb4f32fcba7..6b83a3e7ae28e 100644 --- a/llvm/lib/Target/VE/CMakeLists.txt +++ b/llvm/lib/Target/VE/CMakeLists.txt @@ -4,7 +4,8 @@ set(LLVM_TARGET_DEFINITIONS VE.td) tablegen(LLVM VEGenRegisterInfo.inc -gen-register-info) tablegen(LLVM VEGenInstrInfo.inc -gen-instr-info) -tablegen(LLVM VEGenDisassemblerTables.inc -gen-disassembler) +tablegen(LLVM VEGenDisassemblerTables.inc -gen-disassembler + -non-templated-decode-to-mcinst-type-spec=uint64_t:=64) tablegen(LLVM VEGenMCCodeEmitter.inc -gen-emitter) tablegen(LLVM VEGenAsmWriter.inc -gen-asm-writer) tablegen(LLVM VEGenAsmMatcher.inc -gen-asm-matcher) diff --git a/llvm/lib/Target/XCore/CMakeLists.txt b/llvm/lib/Target/XCore/CMakeLists.txt index f411c658b43b0..3b5bf848d8144 100644 --- a/llvm/lib/Target/XCore/CMakeLists.txt +++ b/llvm/lib/Target/XCore/CMakeLists.txt @@ -5,7 +5,9 @@ set(LLVM_TARGET_DEFINITIONS XCore.td) tablegen(LLVM XCoreGenAsmWriter.inc -gen-asm-writer) tablegen(LLVM XCoreGenCallingConv.inc -gen-callingconv) tablegen(LLVM XCoreGenDAGISel.inc -gen-dag-isel) -tablegen(LLVM XCoreGenDisassemblerTables.inc -gen-disassembler) +tablegen(LLVM XCoreGenDisassemblerTables.inc -gen-disassembler + -non-templated-decode-to-mcinst-type-spec=uint16_t:=16 + -non-templated-decode-to-mcinst-type-spec=uint32_t:=32) tablegen(LLVM XCoreGenInstrInfo.inc -gen-instr-info) tablegen(LLVM XCoreGenRegisterInfo.inc -gen-register-info) tablegen(LLVM XCoreGenSDNodeInfo.inc -gen-sd-node-info) diff --git a/llvm/lib/Target/Xtensa/CMakeLists.txt b/llvm/lib/Target/Xtensa/CMakeLists.txt index 4fc1ba6dfa650..9c825b5d880c7 100644 --- a/llvm/lib/Target/Xtensa/CMakeLists.txt +++ b/llvm/lib/Target/Xtensa/CMakeLists.txt @@ -6,7 +6,8 @@ tablegen(LLVM XtensaGenAsmMatcher.inc -gen-asm-matcher) tablegen(LLVM XtensaGenAsmWriter.inc -gen-asm-writer) tablegen(LLVM XtensaGenCallingConv.inc -gen-callingconv) tablegen(LLVM XtensaGenDAGISel.inc -gen-dag-isel) -tablegen(LLVM XtensaGenDisassemblerTables.inc -gen-disassembler) +tablegen(LLVM XtensaGenDisassemblerTables.inc -gen-disassembler + -non-templated-decode-to-mcinst-type-spec=uint64_t:=16,24) tablegen(LLVM XtensaGenInstrInfo.inc -gen-instr-info) tablegen(LLVM XtensaGenMCCodeEmitter.inc -gen-emitter) tablegen(LLVM XtensaGenRegisterInfo.inc -gen-register-info) diff --git a/llvm/test/TableGen/VarLenDecoder.td b/llvm/test/TableGen/VarLenDecoder.td index 06ff62294a196..2359bd2c15145 100644 --- a/llvm/test/TableGen/VarLenDecoder.td +++ b/llvm/test/TableGen/VarLenDecoder.td @@ -61,11 +61,7 @@ def FOO32 : MyVarInst { // 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 { // CHECK-NEXT: MI.addOperand(MCOperand::createImm(tmp)); // CHECK-NEXT: return S; +// Instruction length table +// CHECK-LABEL: InstrLenTable +// CHECK: 27, +// CHECK-NEXT: 43, +// CHECK-NEXT: }; + +// CHECK-LABEL: decodeInstruction // CHECK-LABEL: case MCD::OPC_ExtractField: { // CHECK: makeUp(insn, Start + Len); diff --git a/llvm/utils/TableGen/DecoderEmitter.cpp b/llvm/utils/TableGen/DecoderEmitter.cpp index d582309a6fd4a..ae3f072601014 100644 --- a/llvm/utils/TableGen/DecoderEmitter.cpp +++ b/llvm/utils/TableGen/DecoderEmitter.cpp @@ -23,6 +23,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallBitVector.h" +#include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/StringExtras.h" @@ -92,6 +93,22 @@ static cl::opt 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 DecodeToMCInstTypeSpecs( + "non-templated-decode-to-mcinst-type-spec", + cl::desc("list of C++ types and associated bitwidths to used to generate " + "non-templated `decodeToMCInst`."), + cl::cat(DisassemblerEmitterCat)); + STATISTIC(NumEncodings, "Number of encodings considered"); STATISTIC(NumEncodingsLackingDisasm, "Number of encodings without disassembler info"); @@ -234,7 +251,7 @@ class DecoderEmitter { void emitPredicateFunction(formatted_raw_ostream &OS, PredicateSet &Predicates, indent Indent) const; void emitDecoderFunction(formatted_raw_ostream &OS, DecoderSet &Decoders, - indent Indent) const; + StringRef SpecializedInsnType, indent Indent) const; // run - Output the code emitter void run(raw_ostream &o); @@ -1068,24 +1085,35 @@ void DecoderEmitter::emitPredicateFunction(formatted_raw_ostream &OS, void DecoderEmitter::emitDecoderFunction(formatted_raw_ostream &OS, DecoderSet &Decoders, + StringRef SpecializedInsnType, indent Indent) const { + auto emitTemplate = [&OS, SpecializedInsnType, &Indent] { + if (SpecializedInsnType.empty()) + OS << Indent << "template \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::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::value, {0}, " + "uint64_t>;\n", + InsnType); + auto DecodeParams = + formatv("DecodeStatus S, {} insn, MCInst &MI, uint64_t Address, const " + "MCDisassembler *Decoder, bool &DecodeComplete", + InsnType); if (UseFnTableInDecodeToMCInst) { // Emit a function for each case first. for (const auto &[Index, Decoder] : enumerate(Decoders)) { - OS << Indent << "template \n"; + emitTemplate(); OS << Indent << "DecodeStatus decodeFn" << Index << "(" << DecodeParams << ") {\n"; Indent += 2; @@ -1099,7 +1127,7 @@ void DecoderEmitter::emitDecoderFunction(formatted_raw_ostream &OS, } OS << Indent << "// Handling " << Decoders.size() << " cases.\n"; - OS << Indent << "template \n"; + emitTemplate(); OS << Indent << "static DecodeStatus decodeToMCInst(unsigned Idx, " << DecodeParams << ") {\n"; Indent += 2; @@ -2538,6 +2566,70 @@ handleHwModesUnrelatedEncodings(const CodeGenInstruction *Instr, } } +// Result of parsing a single `non-templated-decode-to-mcinst-type-spec` option. +using BitwidthSet = SmallSet; +struct NonTemplatedTypeSpec { + StringRef Type; + BitwidthSet Bitwidths; +}; + +static SmallVector +parseNonTemplatedTypeSpec(BitwidthSet &InstrBitwidths) { + SmallVector 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 + // :=. Note, can in general be a templated + // type, so using the token ":=" as a separator to allow many general C++ + // types here. + auto [Type, ListOfBitWidths] = TypeSpec.split(":="); + if (Type.empty()) + PrintFatalError("Invalid typespec: " + TypeSpec); + + for (StringRef BwStr : split(ListOfBitWidths, ',')) { + unsigned Bitwidth; + if (BwStr.getAsInteger(10, Bitwidth)) + PrintFatalError("Invalid bitwidth: " + BwStr + " in typespec " + + TypeSpec); + + if (!OptionBitwidths.insert(Bitwidth).second) + PrintFatalError("Bitwidth " + Twine(Bitwidth) + " already specified."); + + if (!InstrBitwidths.contains(Bitwidth)) + PrintFatalError(Twine("No instruction of Bitwidth ") + Twine(Bitwidth) + + " supported."); + + InstrBitwidths.erase(Bitwidth); + Bitwidths.insert(Bitwidth); + } + + if (Bitwidths.empty()) + PrintFatalError("No bitwidth specified in typespec " + TypeSpec); + + Parsed.emplace_back(NonTemplatedTypeSpec{Type, Bitwidths}); + } + + if (!InstrBitwidths.empty()) { + PrintFatalError([&InstrBitwidths](raw_ostream &OS) { + OS << "Bitwidth(s) "; + llvm::interleaveComma(InstrBitwidths, OS); + OS << " missing in `non-templated-decode-to-mcinst-type-spec` options."; + }); + } + return Parsed; +} + // Emits disassembler code for instruction decoding. void DecoderEmitter::run(raw_ostream &o) { formatted_raw_ostream OS(o); @@ -2649,35 +2741,59 @@ namespace { } } + // Collect all allowed Bitwidths for instructions. + BitwidthSet InstrBitwidths; + for (const auto &[NSAndByteSize, _] : OpcMap) { + const unsigned Bitwidth = 8 * NSAndByteSize.second; + InstrBitwidths.insert(Bitwidth); + } + SmallVector NonTemplatedTypeSpecs = + parseNonTemplatedTypeSpec(InstrBitwidths); + DecoderTableInfo TableInfo; unsigned OpcodeMask = 0; - for (const auto &[NSAndByteSize, EncodingIDs] : OpcMap) { - const std::string &DecoderNamespace = NSAndByteSize.first; - const unsigned BitWidth = 8 * NSAndByteSize.second; - // Emit the decoder for this namespace+width combination. - FilterChooser FC(NumberedEncodings, EncodingIDs, Operands, - IsVarLenInst ? MaxInstLen : BitWidth, this); - - // The decode table is cleared for each top level decoder function. The - // predicates and decoders themselves, however, are shared across all - // decoders to give more opportunities for uniqueing. - TableInfo.Table.clear(); - TableInfo.FixupStack.clear(); - TableInfo.FixupStack.emplace_back(); - FC.emitTableEntries(TableInfo); - // Any NumToSkip fixups in the top level scope can resolve to the - // OPC_Fail at the end of the table. - assert(TableInfo.FixupStack.size() == 1 && "fixup stack phasing error!"); - // Resolve any NumToSkip fixups in the current scope. - resolveTableFixups(TableInfo.Table, TableInfo.FixupStack.back(), - TableInfo.Table.size()); - TableInfo.FixupStack.clear(); + for (const auto &[NTType, NTBitwidths] : NonTemplatedTypeSpecs) { + // Reset the Decoders for each non-templated type. + TableInfo.Decoders.clear(); + + for (const auto &[NSAndByteSize, EncodingIDs] : OpcMap) { + const std::string &DecoderNamespace = NSAndByteSize.first; + const unsigned InstrBitwidth = + IsVarLenInst ? MaxInstLen : 8 * NSAndByteSize.second; + + // Only handle instruction of the non-templated bitwidth size when + // non-templated bitwidth option is enabled. + if (!NTBitwidths.empty() && !NTBitwidths.contains(InstrBitwidth)) + continue; + + // Emit the decoder for this namespace+width combination. + FilterChooser FC(NumberedEncodings, EncodingIDs, Operands, + IsVarLenInst ? MaxInstLen : InstrBitwidth, this); + + // The decode table is cleared for each top level decoder function. The + // predicates and decoders themselves, however, are shared across all + // decoders to give more opportunities for uniqueing. + TableInfo.Table.clear(); + TableInfo.FixupStack.clear(); + TableInfo.FixupStack.emplace_back(); + FC.emitTableEntries(TableInfo); + // Any NumToSkip fixups in the top level scope can resolve to the + // OPC_Fail at the end of the table. + assert(TableInfo.FixupStack.size() == 1 && "fixup stack phasing error!"); + // Resolve any NumToSkip fixups in the current scope. + resolveTableFixups(TableInfo.Table, TableInfo.FixupStack.back(), + TableInfo.Table.size()); + TableInfo.FixupStack.clear(); - TableInfo.Table.push_back(MCD::OPC_Fail); + TableInfo.Table.push_back(MCD::OPC_Fail); - // Print the table to the output stream. - OpcodeMask |= emitTable(OS, TableInfo.Table, indent(0), FC.getBitWidth(), - DecoderNamespace, EncodingIDs); + // Print the table to the output stream. + OpcodeMask |= emitTable(OS, TableInfo.Table, indent(0), FC.getBitWidth(), + DecoderNamespace, EncodingIDs); + } + + // Emit the decoder function for this BitWidth. + emitDecoderFunction(OS, TableInfo.Decoders, NTType, indent(0)); } // For variable instruction, we emit a instruction length table @@ -2694,9 +2810,6 @@ namespace { if (HasCheckPredicate) emitPredicateFunction(OS, TableInfo.Predicates, indent(0)); - // Emit the decoder function. - emitDecoderFunction(OS, TableInfo.Decoders, indent(0)); - // Emit the main entry point for the decoder, decodeInstruction(). emitDecodeInstruction(OS, IsVarLenInst, OpcodeMask); From 04366eedc71984255b2792be4ff32babd33f3668 Mon Sep 17 00:00:00 2001 From: Rahul Joshi Date: Wed, 2 Jul 2025 06:53:54 -0700 Subject: [PATCH 2/5] Review feedback --- llvm/include/llvm/TableGen/Record.h | 2 + llvm/include/llvm/Target/Target.td | 19 ++++ llvm/lib/TableGen/Record.cpp | 43 +++++----- llvm/lib/Target/AArch64/AArch64.td | 6 +- llvm/lib/Target/AArch64/CMakeLists.txt | 3 +- llvm/lib/Target/AMDGPU/CMakeLists.txt | 5 +- llvm/lib/Target/ARC/CMakeLists.txt | 4 +- llvm/lib/Target/ARM/CMakeLists.txt | 4 +- llvm/lib/Target/AVR/CMakeLists.txt | 3 +- llvm/lib/Target/BPF/CMakeLists.txt | 3 +- llvm/lib/Target/CSKY/CMakeLists.txt | 3 +- llvm/lib/Target/Hexagon/CMakeLists.txt | 3 +- llvm/lib/Target/Lanai/CMakeLists.txt | 3 +- llvm/lib/Target/LoongArch/CMakeLists.txt | 3 +- llvm/lib/Target/MSP430/CMakeLists.txt | 3 +- llvm/lib/Target/Mips/CMakeLists.txt | 3 +- llvm/lib/Target/PowerPC/CMakeLists.txt | 3 +- llvm/lib/Target/RISCV/CMakeLists.txt | 4 +- llvm/lib/Target/RISCV/RISCV.td | 4 + llvm/lib/Target/Sparc/CMakeLists.txt | 3 +- llvm/lib/Target/SystemZ/CMakeLists.txt | 3 +- llvm/lib/Target/VE/CMakeLists.txt | 3 +- llvm/lib/Target/XCore/CMakeLists.txt | 4 +- llvm/lib/Target/Xtensa/CMakeLists.txt | 3 +- llvm/utils/TableGen/DecoderEmitter.cpp | 105 +++++++++++------------ 25 files changed, 120 insertions(+), 122 deletions(-) diff --git a/llvm/include/llvm/TableGen/Record.h b/llvm/include/llvm/TableGen/Record.h index 5849344bcb0b5..306988cd0fc53 100644 --- a/llvm/include/llvm/TableGen/Record.h +++ b/llvm/include/llvm/TableGen/Record.h @@ -803,6 +803,8 @@ class ListInit final : public TypedInit, size_t size() const { return NumElements; } bool empty() const { return NumElements == 0; } + std::vector getAsListOfInts() const; + const Init *getBit(unsigned Bit) const override { llvm_unreachable("Illegal bit reference off list"); } diff --git a/llvm/include/llvm/Target/Target.td b/llvm/include/llvm/Target/Target.td index ce9a2b2751968..e2e711baaede2 100644 --- a/llvm/include/llvm/Target/Target.td +++ b/llvm/include/llvm/Target/Target.td @@ -1158,6 +1158,25 @@ class InstrInfo { // // This option is a temporary migration help. It will go away. bit guessInstructionProperties = true; + + // These properties, when set, opt into the non-templated variants of + // `decodeToMCInst` generated by TableGen DecoderEmitter backend. Using this + // option helps reduce the code size of the generated code as compared to the + // templated `decodeToMCInst` that is generated by default. + // For each index `I`, InsnCPPTypes[I] is a C++ type that will be used to + // generate a non-templated `decodeToMCInst`, and InstBitwidths[I] is a list + // instruction bitwidth(s) whose decoders will be included in the generated + // code. + list InsnCPPTypes = []; + list> InsnBitwidths = []; + assert !eq(!size(InsnCPPTypes), !size(InsnBitwidths)), + "The InsnCPPTypes and InsnBitwidths lists must be the same length"; + + // Make sure the InstCPPTypes, if not empty, does not contain empty strings. + assert !or(!empty(InsnCPPTypes), !empty(!filter(e, InsnCPPTypes, !empty(e)))), + "Entries in InstCPPTypes cannot be empty"; + + // Make sure that InsnBitwidths, if not empty, does not contain empty list. } // Standard Pseudo Instructions. diff --git a/llvm/lib/TableGen/Record.cpp b/llvm/lib/TableGen/Record.cpp index 7f2ed77a74099..69f6fa6edb49b 100644 --- a/llvm/lib/TableGen/Record.cpp +++ b/llvm/lib/TableGen/Record.cpp @@ -804,6 +804,15 @@ std::string ListInit::getAsString() const { return Result + "]"; } +std::vector ListInit::getAsListOfInts() const { + if (!isa(getElementType())) + PrintFatalError("List does not contain integer values"); + std::vector Ints; + for (const Init *I : getElements()) + Ints.push_back(cast(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 Record::getValueAsListOfInts(StringRef FieldName) const { const ListInit *List = getValueAsListInit(FieldName); - std::vector Ints; - for (const Init *I : List->getElements()) { - if (const auto *II = dyn_cast(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(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 Record::getValueAsListOfStrings(StringRef FieldName) const { const ListInit *List = getValueAsListInit(FieldName); + if (!isa(List->getElementType())) + PrintFatalError(getLoc(), + Twine("Record `") + getName() + "', field `" + FieldName + + "' exists but does not have a list of string value: " + + List->getAsString()); + std::vector Strings; - for (const Init *I : List->getElements()) { - if (const auto *SI = dyn_cast(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(I)->getValue()); return Strings; } diff --git a/llvm/lib/Target/AArch64/AArch64.td b/llvm/lib/Target/AArch64/AArch64.td index 25cdcae4e41de..670027d59acde 100644 --- a/llvm/lib/Target/AArch64/AArch64.td +++ b/llvm/lib/Target/AArch64/AArch64.td @@ -40,7 +40,11 @@ include "AArch64SchedPredExynos.td" include "AArch64SchedPredNeoverse.td" include "AArch64Combine.td" -def AArch64InstrInfo : InstrInfo; +def AArch64InstrInfo : InstrInfo { + // Opt-in into non-templated code for instruction decoder. + let InsnCPPTypes = ["uint32_t"]; + let InsnBitwidths = [[32]]; +} //===----------------------------------------------------------------------===// // Named operands for MRS/MSR/TLBI/... diff --git a/llvm/lib/Target/AArch64/CMakeLists.txt b/llvm/lib/Target/AArch64/CMakeLists.txt index 98cc8693144f0..66136a464f05d 100644 --- a/llvm/lib/Target/AArch64/CMakeLists.txt +++ b/llvm/lib/Target/AArch64/CMakeLists.txt @@ -7,8 +7,7 @@ tablegen(LLVM AArch64GenAsmWriter.inc -gen-asm-writer) tablegen(LLVM AArch64GenAsmWriter1.inc -gen-asm-writer -asmwriternum=1) tablegen(LLVM AArch64GenCallingConv.inc -gen-callingconv) tablegen(LLVM AArch64GenDAGISel.inc -gen-dag-isel) -tablegen(LLVM AArch64GenDisassemblerTables.inc -gen-disassembler - -non-templated-decode-to-mcinst-type-spec=uint32_t:=32) +tablegen(LLVM AArch64GenDisassemblerTables.inc -gen-disassembler) tablegen(LLVM AArch64GenFastISel.inc -gen-fast-isel) tablegen(LLVM AArch64GenGlobalISel.inc -gen-global-isel) tablegen(LLVM AArch64GenO0PreLegalizeGICombiner.inc -gen-global-isel-combiner diff --git a/llvm/lib/Target/AMDGPU/CMakeLists.txt b/llvm/lib/Target/AMDGPU/CMakeLists.txt index 6254750c10c3c..e3519f192137c 100644 --- a/llvm/lib/Target/AMDGPU/CMakeLists.txt +++ b/llvm/lib/Target/AMDGPU/CMakeLists.txt @@ -6,10 +6,7 @@ tablegen(LLVM AMDGPUGenAsmMatcher.inc -gen-asm-matcher) tablegen(LLVM AMDGPUGenAsmWriter.inc -gen-asm-writer) tablegen(LLVM AMDGPUGenCallingConv.inc -gen-callingconv) tablegen(LLVM AMDGPUGenDAGISel.inc -gen-dag-isel) -tablegen(LLVM AMDGPUGenDisassemblerTables.inc -gen-disassembler - -non-templated-decode-to-mcinst-type-spec=uint32_t:=32 - -non-templated-decode-to-mcinst-type-spec=uint64_t:=64 - -non-templated-decode-to-mcinst-type-spec=DecoderUInt128:=96,128) +tablegen(LLVM AMDGPUGenDisassemblerTables.inc -gen-disassembler) tablegen(LLVM AMDGPUGenInstrInfo.inc -gen-instr-info) tablegen(LLVM AMDGPUGenMCCodeEmitter.inc -gen-emitter) tablegen(LLVM AMDGPUGenMCPseudoLowering.inc -gen-pseudo-lowering) diff --git a/llvm/lib/Target/ARC/CMakeLists.txt b/llvm/lib/Target/ARC/CMakeLists.txt index e6656576fbcc3..196cc31cc5080 100644 --- a/llvm/lib/Target/ARC/CMakeLists.txt +++ b/llvm/lib/Target/ARC/CMakeLists.txt @@ -5,9 +5,7 @@ set(LLVM_TARGET_DEFINITIONS ARC.td) tablegen(LLVM ARCGenAsmWriter.inc -gen-asm-writer) tablegen(LLVM ARCGenCallingConv.inc -gen-callingconv) tablegen(LLVM ARCGenDAGISel.inc -gen-dag-isel) -tablegen(LLVM ARCGenDisassemblerTables.inc -gen-disassembler - -non-templated-decode-to-mcinst-type-spec=uint32_t:=16,32 - -non-templated-decode-to-mcinst-type-spec=uint64_t:=48,64) +tablegen(LLVM ARCGenDisassemblerTables.inc -gen-disassembler) tablegen(LLVM ARCGenInstrInfo.inc -gen-instr-info) tablegen(LLVM ARCGenRegisterInfo.inc -gen-register-info) tablegen(LLVM ARCGenSDNodeInfo.inc -gen-sd-node-info) diff --git a/llvm/lib/Target/ARM/CMakeLists.txt b/llvm/lib/Target/ARM/CMakeLists.txt index 718a084ec6388..a39629bd8aeb0 100644 --- a/llvm/lib/Target/ARM/CMakeLists.txt +++ b/llvm/lib/Target/ARM/CMakeLists.txt @@ -6,9 +6,7 @@ tablegen(LLVM ARMGenAsmMatcher.inc -gen-asm-matcher) tablegen(LLVM ARMGenAsmWriter.inc -gen-asm-writer) tablegen(LLVM ARMGenCallingConv.inc -gen-callingconv) tablegen(LLVM ARMGenDAGISel.inc -gen-dag-isel) -tablegen(LLVM ARMGenDisassemblerTables.inc -gen-disassembler - -non-templated-decode-to-mcinst-type-spec=uint16_t:=16 - -non-templated-decode-to-mcinst-type-spec=uint32_t:=32) +tablegen(LLVM ARMGenDisassemblerTables.inc -gen-disassembler) tablegen(LLVM ARMGenFastISel.inc -gen-fast-isel) tablegen(LLVM ARMGenGlobalISel.inc -gen-global-isel) tablegen(LLVM ARMGenInstrInfo.inc -gen-instr-info) diff --git a/llvm/lib/Target/AVR/CMakeLists.txt b/llvm/lib/Target/AVR/CMakeLists.txt index a2da85d77a325..781dac02c7083 100644 --- a/llvm/lib/Target/AVR/CMakeLists.txt +++ b/llvm/lib/Target/AVR/CMakeLists.txt @@ -6,8 +6,7 @@ tablegen(LLVM AVRGenAsmMatcher.inc -gen-asm-matcher) tablegen(LLVM AVRGenAsmWriter.inc -gen-asm-writer) tablegen(LLVM AVRGenCallingConv.inc -gen-callingconv) tablegen(LLVM AVRGenDAGISel.inc -gen-dag-isel) -tablegen(LLVM AVRGenDisassemblerTables.inc -gen-disassembler - -non-templated-decode-to-mcinst-type-spec=uint32_t:=16,32) +tablegen(LLVM AVRGenDisassemblerTables.inc -gen-disassembler) tablegen(LLVM AVRGenInstrInfo.inc -gen-instr-info) tablegen(LLVM AVRGenMCCodeEmitter.inc -gen-emitter) tablegen(LLVM AVRGenRegisterInfo.inc -gen-register-info) diff --git a/llvm/lib/Target/BPF/CMakeLists.txt b/llvm/lib/Target/BPF/CMakeLists.txt index 6a609d645dfa1..eade4cacb7100 100644 --- a/llvm/lib/Target/BPF/CMakeLists.txt +++ b/llvm/lib/Target/BPF/CMakeLists.txt @@ -6,8 +6,7 @@ tablegen(LLVM BPFGenAsmMatcher.inc -gen-asm-matcher) tablegen(LLVM BPFGenAsmWriter.inc -gen-asm-writer) tablegen(LLVM BPFGenCallingConv.inc -gen-callingconv) tablegen(LLVM BPFGenDAGISel.inc -gen-dag-isel) -tablegen(LLVM BPFGenDisassemblerTables.inc -gen-disassembler - -non-templated-decode-to-mcinst-type-spec=uint64_t:=64) +tablegen(LLVM BPFGenDisassemblerTables.inc -gen-disassembler) tablegen(LLVM BPFGenInstrInfo.inc -gen-instr-info) tablegen(LLVM BPFGenMCCodeEmitter.inc -gen-emitter) tablegen(LLVM BPFGenRegisterInfo.inc -gen-register-info) diff --git a/llvm/lib/Target/CSKY/CMakeLists.txt b/llvm/lib/Target/CSKY/CMakeLists.txt index eadf0169edef1..4b900bc99c271 100644 --- a/llvm/lib/Target/CSKY/CMakeLists.txt +++ b/llvm/lib/Target/CSKY/CMakeLists.txt @@ -7,8 +7,7 @@ tablegen(LLVM CSKYGenAsmWriter.inc -gen-asm-writer) tablegen(LLVM CSKYGenCallingConv.inc -gen-callingconv) tablegen(LLVM CSKYGenCompressInstEmitter.inc -gen-compress-inst-emitter) tablegen(LLVM CSKYGenDAGISel.inc -gen-dag-isel) -tablegen(LLVM CSKYGenDisassemblerTables.inc -gen-disassembler - -non-templated-decode-to-mcinst-type-spec=uint32_t:=16,32) +tablegen(LLVM CSKYGenDisassemblerTables.inc -gen-disassembler) tablegen(LLVM CSKYGenInstrInfo.inc -gen-instr-info) tablegen(LLVM CSKYGenMCCodeEmitter.inc -gen-emitter) tablegen(LLVM CSKYGenMCPseudoLowering.inc -gen-pseudo-lowering) diff --git a/llvm/lib/Target/Hexagon/CMakeLists.txt b/llvm/lib/Target/Hexagon/CMakeLists.txt index be2bc89155612..d758260a8ab5d 100644 --- a/llvm/lib/Target/Hexagon/CMakeLists.txt +++ b/llvm/lib/Target/Hexagon/CMakeLists.txt @@ -7,8 +7,7 @@ tablegen(LLVM HexagonGenAsmWriter.inc -gen-asm-writer) tablegen(LLVM HexagonGenCallingConv.inc -gen-callingconv) tablegen(LLVM HexagonGenDAGISel.inc -gen-dag-isel) tablegen(LLVM HexagonGenDFAPacketizer.inc -gen-dfa-packetizer) -tablegen(LLVM HexagonGenDisassemblerTables.inc -gen-disassembler - -non-templated-decode-to-mcinst-type-spec=uint32_t:=32) +tablegen(LLVM HexagonGenDisassemblerTables.inc -gen-disassembler) tablegen(LLVM HexagonGenInstrInfo.inc -gen-instr-info) tablegen(LLVM HexagonGenMCCodeEmitter.inc -gen-emitter) tablegen(LLVM HexagonGenRegisterInfo.inc -gen-register-info) diff --git a/llvm/lib/Target/Lanai/CMakeLists.txt b/llvm/lib/Target/Lanai/CMakeLists.txt index dfb0c93e1a5e3..4a628e13fc177 100644 --- a/llvm/lib/Target/Lanai/CMakeLists.txt +++ b/llvm/lib/Target/Lanai/CMakeLists.txt @@ -6,8 +6,7 @@ tablegen(LLVM LanaiGenAsmMatcher.inc -gen-asm-matcher) tablegen(LLVM LanaiGenAsmWriter.inc -gen-asm-writer) tablegen(LLVM LanaiGenCallingConv.inc -gen-callingconv) tablegen(LLVM LanaiGenDAGISel.inc -gen-dag-isel) -tablegen(LLVM LanaiGenDisassemblerTables.inc -gen-disassembler - -non-templated-decode-to-mcinst-type-spec=uint32_t:=32) +tablegen(LLVM LanaiGenDisassemblerTables.inc -gen-disassembler) tablegen(LLVM LanaiGenInstrInfo.inc -gen-instr-info) tablegen(LLVM LanaiGenMCCodeEmitter.inc -gen-emitter) tablegen(LLVM LanaiGenRegisterInfo.inc -gen-register-info) diff --git a/llvm/lib/Target/LoongArch/CMakeLists.txt b/llvm/lib/Target/LoongArch/CMakeLists.txt index c851f5c2fc1da..0f674b1b0fa9e 100644 --- a/llvm/lib/Target/LoongArch/CMakeLists.txt +++ b/llvm/lib/Target/LoongArch/CMakeLists.txt @@ -5,8 +5,7 @@ set(LLVM_TARGET_DEFINITIONS LoongArch.td) tablegen(LLVM LoongArchGenAsmMatcher.inc -gen-asm-matcher) tablegen(LLVM LoongArchGenAsmWriter.inc -gen-asm-writer) tablegen(LLVM LoongArchGenDAGISel.inc -gen-dag-isel) -tablegen(LLVM LoongArchGenDisassemblerTables.inc -gen-disassembler - -non-templated-decode-to-mcinst-type-spec=uint32_t:=32) +tablegen(LLVM LoongArchGenDisassemblerTables.inc -gen-disassembler) tablegen(LLVM LoongArchGenInstrInfo.inc -gen-instr-info) tablegen(LLVM LoongArchGenMCPseudoLowering.inc -gen-pseudo-lowering) tablegen(LLVM LoongArchGenMCCodeEmitter.inc -gen-emitter) diff --git a/llvm/lib/Target/MSP430/CMakeLists.txt b/llvm/lib/Target/MSP430/CMakeLists.txt index f10c8192e7df0..4081d3472fd78 100644 --- a/llvm/lib/Target/MSP430/CMakeLists.txt +++ b/llvm/lib/Target/MSP430/CMakeLists.txt @@ -6,8 +6,7 @@ tablegen(LLVM MSP430GenAsmMatcher.inc -gen-asm-matcher) tablegen(LLVM MSP430GenAsmWriter.inc -gen-asm-writer) tablegen(LLVM MSP430GenCallingConv.inc -gen-callingconv) tablegen(LLVM MSP430GenDAGISel.inc -gen-dag-isel) -tablegen(LLVM MSP430GenDisassemblerTables.inc -gen-disassembler - -non-templated-decode-to-mcinst-type-spec=uint64_t:=16,32,48) +tablegen(LLVM MSP430GenDisassemblerTables.inc -gen-disassembler) tablegen(LLVM MSP430GenInstrInfo.inc -gen-instr-info) tablegen(LLVM MSP430GenMCCodeEmitter.inc -gen-emitter) tablegen(LLVM MSP430GenRegisterInfo.inc -gen-register-info) diff --git a/llvm/lib/Target/Mips/CMakeLists.txt b/llvm/lib/Target/Mips/CMakeLists.txt index 2516d00706a91..21d1765107ae6 100644 --- a/llvm/lib/Target/Mips/CMakeLists.txt +++ b/llvm/lib/Target/Mips/CMakeLists.txt @@ -6,8 +6,7 @@ tablegen(LLVM MipsGenAsmMatcher.inc -gen-asm-matcher) tablegen(LLVM MipsGenAsmWriter.inc -gen-asm-writer) tablegen(LLVM MipsGenCallingConv.inc -gen-callingconv) tablegen(LLVM MipsGenDAGISel.inc -gen-dag-isel) -tablegen(LLVM MipsGenDisassemblerTables.inc -gen-disassembler - -non-templated-decode-to-mcinst-type-spec=uint32_t:=16,32) +tablegen(LLVM MipsGenDisassemblerTables.inc -gen-disassembler) tablegen(LLVM MipsGenFastISel.inc -gen-fast-isel) tablegen(LLVM MipsGenGlobalISel.inc -gen-global-isel) tablegen(LLVM MipsGenPostLegalizeGICombiner.inc -gen-global-isel-combiner diff --git a/llvm/lib/Target/PowerPC/CMakeLists.txt b/llvm/lib/Target/PowerPC/CMakeLists.txt index 136db0634eb93..3808a26a0b92a 100644 --- a/llvm/lib/Target/PowerPC/CMakeLists.txt +++ b/llvm/lib/Target/PowerPC/CMakeLists.txt @@ -6,8 +6,7 @@ tablegen(LLVM PPCGenAsmMatcher.inc -gen-asm-matcher) tablegen(LLVM PPCGenAsmWriter.inc -gen-asm-writer) tablegen(LLVM PPCGenCallingConv.inc -gen-callingconv) tablegen(LLVM PPCGenDAGISel.inc -gen-dag-isel) -tablegen(LLVM PPCGenDisassemblerTables.inc -gen-disassembler - -non-templated-decode-to-mcinst-type-spec=uint64_t:=32,64) +tablegen(LLVM PPCGenDisassemblerTables.inc -gen-disassembler) tablegen(LLVM PPCGenFastISel.inc -gen-fast-isel) tablegen(LLVM PPCGenInstrInfo.inc -gen-instr-info) tablegen(LLVM PPCGenMCCodeEmitter.inc -gen-emitter) diff --git a/llvm/lib/Target/RISCV/CMakeLists.txt b/llvm/lib/Target/RISCV/CMakeLists.txt index 9df6701387d43..e32d6eab3b977 100644 --- a/llvm/lib/Target/RISCV/CMakeLists.txt +++ b/llvm/lib/Target/RISCV/CMakeLists.txt @@ -7,9 +7,7 @@ tablegen(LLVM RISCVGenAsmWriter.inc -gen-asm-writer) tablegen(LLVM RISCVGenCompressInstEmitter.inc -gen-compress-inst-emitter) tablegen(LLVM RISCVGenMacroFusion.inc -gen-macro-fusion-pred) tablegen(LLVM RISCVGenDAGISel.inc -gen-dag-isel) -tablegen(LLVM RISCVGenDisassemblerTables.inc -gen-disassembler - -non-templated-decode-to-mcinst-type-spec=uint32_t:=16,32 - -non-templated-decode-to-mcinst-type-spec=uint64_t:=48) +tablegen(LLVM RISCVGenDisassemblerTables.inc -gen-disassembler) tablegen(LLVM RISCVGenInstrInfo.inc -gen-instr-info) tablegen(LLVM RISCVGenMCCodeEmitter.inc -gen-emitter) tablegen(LLVM RISCVGenMCPseudoLowering.inc -gen-pseudo-lowering) diff --git a/llvm/lib/Target/RISCV/RISCV.td b/llvm/lib/Target/RISCV/RISCV.td index b24d8637cb27f..b3ce392d27a17 100644 --- a/llvm/lib/Target/RISCV/RISCV.td +++ b/llvm/lib/Target/RISCV/RISCV.td @@ -85,6 +85,10 @@ include "RISCVPfmCounters.td" def RISCVInstrInfo : InstrInfo { let guessInstructionProperties = 0; + + // Opt-in into non-templated code for instruction decoder. + let InsnCPPTypes = ["uint64_t"]; + let InsnBitwidths = [[16, 32, 48]]; } def RISCVAsmParser : AsmParser { diff --git a/llvm/lib/Target/Sparc/CMakeLists.txt b/llvm/lib/Target/Sparc/CMakeLists.txt index 6334dbbc6cc1a..f682719ac483f 100644 --- a/llvm/lib/Target/Sparc/CMakeLists.txt +++ b/llvm/lib/Target/Sparc/CMakeLists.txt @@ -6,8 +6,7 @@ tablegen(LLVM SparcGenAsmMatcher.inc -gen-asm-matcher) tablegen(LLVM SparcGenAsmWriter.inc -gen-asm-writer) tablegen(LLVM SparcGenCallingConv.inc -gen-callingconv) tablegen(LLVM SparcGenDAGISel.inc -gen-dag-isel) -tablegen(LLVM SparcGenDisassemblerTables.inc -gen-disassembler - -non-templated-decode-to-mcinst-type-spec=uint32_t:=32) +tablegen(LLVM SparcGenDisassemblerTables.inc -gen-disassembler) tablegen(LLVM SparcGenInstrInfo.inc -gen-instr-info) tablegen(LLVM SparcGenMCCodeEmitter.inc -gen-emitter) tablegen(LLVM SparcGenRegisterInfo.inc -gen-register-info) diff --git a/llvm/lib/Target/SystemZ/CMakeLists.txt b/llvm/lib/Target/SystemZ/CMakeLists.txt index 1caeef468f3fb..0d8f3eac6ee4f 100644 --- a/llvm/lib/Target/SystemZ/CMakeLists.txt +++ b/llvm/lib/Target/SystemZ/CMakeLists.txt @@ -7,8 +7,7 @@ tablegen(LLVM SystemZGenGNUAsmWriter.inc -gen-asm-writer) tablegen(LLVM SystemZGenHLASMAsmWriter.inc -gen-asm-writer -asmwriternum=1) tablegen(LLVM SystemZGenCallingConv.inc -gen-callingconv) tablegen(LLVM SystemZGenDAGISel.inc -gen-dag-isel) -tablegen(LLVM SystemZGenDisassemblerTables.inc -gen-disassembler - -non-templated-decode-to-mcinst-type-spec=uint64_t:=16,32,48) +tablegen(LLVM SystemZGenDisassemblerTables.inc -gen-disassembler) tablegen(LLVM SystemZGenInstrInfo.inc -gen-instr-info) tablegen(LLVM SystemZGenMCCodeEmitter.inc -gen-emitter) tablegen(LLVM SystemZGenRegisterInfo.inc -gen-register-info) diff --git a/llvm/lib/Target/VE/CMakeLists.txt b/llvm/lib/Target/VE/CMakeLists.txt index 6b83a3e7ae28e..d1bb4f32fcba7 100644 --- a/llvm/lib/Target/VE/CMakeLists.txt +++ b/llvm/lib/Target/VE/CMakeLists.txt @@ -4,8 +4,7 @@ set(LLVM_TARGET_DEFINITIONS VE.td) tablegen(LLVM VEGenRegisterInfo.inc -gen-register-info) tablegen(LLVM VEGenInstrInfo.inc -gen-instr-info) -tablegen(LLVM VEGenDisassemblerTables.inc -gen-disassembler - -non-templated-decode-to-mcinst-type-spec=uint64_t:=64) +tablegen(LLVM VEGenDisassemblerTables.inc -gen-disassembler) tablegen(LLVM VEGenMCCodeEmitter.inc -gen-emitter) tablegen(LLVM VEGenAsmWriter.inc -gen-asm-writer) tablegen(LLVM VEGenAsmMatcher.inc -gen-asm-matcher) diff --git a/llvm/lib/Target/XCore/CMakeLists.txt b/llvm/lib/Target/XCore/CMakeLists.txt index 3b5bf848d8144..f411c658b43b0 100644 --- a/llvm/lib/Target/XCore/CMakeLists.txt +++ b/llvm/lib/Target/XCore/CMakeLists.txt @@ -5,9 +5,7 @@ set(LLVM_TARGET_DEFINITIONS XCore.td) tablegen(LLVM XCoreGenAsmWriter.inc -gen-asm-writer) tablegen(LLVM XCoreGenCallingConv.inc -gen-callingconv) tablegen(LLVM XCoreGenDAGISel.inc -gen-dag-isel) -tablegen(LLVM XCoreGenDisassemblerTables.inc -gen-disassembler - -non-templated-decode-to-mcinst-type-spec=uint16_t:=16 - -non-templated-decode-to-mcinst-type-spec=uint32_t:=32) +tablegen(LLVM XCoreGenDisassemblerTables.inc -gen-disassembler) tablegen(LLVM XCoreGenInstrInfo.inc -gen-instr-info) tablegen(LLVM XCoreGenRegisterInfo.inc -gen-register-info) tablegen(LLVM XCoreGenSDNodeInfo.inc -gen-sd-node-info) diff --git a/llvm/lib/Target/Xtensa/CMakeLists.txt b/llvm/lib/Target/Xtensa/CMakeLists.txt index 9c825b5d880c7..4fc1ba6dfa650 100644 --- a/llvm/lib/Target/Xtensa/CMakeLists.txt +++ b/llvm/lib/Target/Xtensa/CMakeLists.txt @@ -6,8 +6,7 @@ tablegen(LLVM XtensaGenAsmMatcher.inc -gen-asm-matcher) tablegen(LLVM XtensaGenAsmWriter.inc -gen-asm-writer) tablegen(LLVM XtensaGenCallingConv.inc -gen-callingconv) tablegen(LLVM XtensaGenDAGISel.inc -gen-dag-isel) -tablegen(LLVM XtensaGenDisassemblerTables.inc -gen-disassembler - -non-templated-decode-to-mcinst-type-spec=uint64_t:=16,24) +tablegen(LLVM XtensaGenDisassemblerTables.inc -gen-disassembler) tablegen(LLVM XtensaGenInstrInfo.inc -gen-instr-info) tablegen(LLVM XtensaGenMCCodeEmitter.inc -gen-emitter) tablegen(LLVM XtensaGenRegisterInfo.inc -gen-register-info) diff --git a/llvm/utils/TableGen/DecoderEmitter.cpp b/llvm/utils/TableGen/DecoderEmitter.cpp index ae3f072601014..7656baddccba1 100644 --- a/llvm/utils/TableGen/DecoderEmitter.cpp +++ b/llvm/utils/TableGen/DecoderEmitter.cpp @@ -93,22 +93,6 @@ static cl::opt 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 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; using NamespacesHwModesMap = std::map>; +// Result of parsing the `InsnCPPTypes` and `InstBitwidths` fields in the Target +// instruction set. +using BitwidthSet = SmallSet; +struct NonTemplatedInsnType { + StringRef CPPType; + BitwidthSet Bitwidths; +}; + class DecoderEmitter { const RecordKeeper &RK; std::vector NumberedEncodings; @@ -257,6 +249,8 @@ class DecoderEmitter { void run(raw_ostream &o); private: + SmallVector + parseNonTemplatedInsnTypes(BitwidthSet &InstrBitwidths); CodeGenTarget Target; public: @@ -2565,66 +2559,63 @@ handleHwModesUnrelatedEncodings(const CodeGenInstruction *Instr, break; } } +SmallVector +DecoderEmitter::parseNonTemplatedInsnTypes(BitwidthSet &InstrBitwidths) { + SmallVector Parsed; -// Result of parsing a single `non-templated-decode-to-mcinst-type-spec` option. -using BitwidthSet = SmallSet; -struct NonTemplatedTypeSpec { - StringRef Type; - BitwidthSet Bitwidths; -}; + const Record *InstructionSet = Target.getInstructionSet(); + std::vector InsnCPPTypes = + InstructionSet->getValueAsListOfStrings("InsnCPPTypes"); -static SmallVector -parseNonTemplatedTypeSpec(BitwidthSet &InstrBitwidths) { - SmallVector 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 - // :=. Note, 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(BWL); + if (!BitwidthList || BitwidthList->empty()) + PrintFatalError(BitwidthsLoc, + "No bitwidths specified for InsnCPPType : " + CPPType); + + for (int64_t Bitwidth : BitwidthList->getAsListOfInts()) { if (!OptionBitwidths.insert(Bitwidth).second) - PrintFatalError("Bitwidth " + Twine(Bitwidth) + " already specified."); + PrintFatalError(BitwidthsLoc, + "Bitwidth " + Twine(Bitwidth) + " already specified."); if (!InstrBitwidths.contains(Bitwidth)) - PrintFatalError(Twine("No instruction of Bitwidth ") + Twine(Bitwidth) + - " supported."); - + PrintFatalError(BitwidthsLoc, "No instruction of bitwidth " + + Twine(Bitwidth) + " supported."); InstrBitwidths.erase(Bitwidth); Bitwidths.insert(Bitwidth); } - - if (Bitwidths.empty()) - PrintFatalError("No bitwidth specified in typespec " + TypeSpec); - - Parsed.emplace_back(NonTemplatedTypeSpec{Type, Bitwidths}); + Parsed.emplace_back(NonTemplatedInsnType{CPPType, Bitwidths}); } if (!InstrBitwidths.empty()) { + // FIXME: Add PrintFatalError that accepts a location and a function_ref. PrintFatalError([&InstrBitwidths](raw_ostream &OS) { OS << "Bitwidth(s) "; - llvm::interleaveComma(InstrBitwidths, OS); - OS << " missing in `non-templated-decode-to-mcinst-type-spec` options."; + interleaveComma(InstrBitwidths, OS); + OS << " missing in `InsnBitwidths`"; }); } return Parsed; @@ -2747,12 +2738,12 @@ namespace { const unsigned Bitwidth = 8 * NSAndByteSize.second; InstrBitwidths.insert(Bitwidth); } - SmallVector NonTemplatedTypeSpecs = - parseNonTemplatedTypeSpec(InstrBitwidths); + SmallVector NonTemplatedInsnTypes = + parseNonTemplatedInsnTypes(InstrBitwidths); DecoderTableInfo TableInfo; unsigned OpcodeMask = 0; - for (const auto &[NTType, NTBitwidths] : NonTemplatedTypeSpecs) { + for (const auto &[NTType, NTBitwidths] : NonTemplatedInsnTypes) { // Reset the Decoders for each non-templated type. TableInfo.Decoders.clear(); From 26588554e04dc9641c323d11fe0f0a40f230f5d7 Mon Sep 17 00:00:00 2001 From: Rahul Joshi Date: Wed, 2 Jul 2025 14:31:28 -0700 Subject: [PATCH 3/5] Specialize decodeInstruction --- llvm/utils/TableGen/DecoderEmitter.cpp | 27 ++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/llvm/utils/TableGen/DecoderEmitter.cpp b/llvm/utils/TableGen/DecoderEmitter.cpp index 7656baddccba1..00123c62b6724 100644 --- a/llvm/utils/TableGen/DecoderEmitter.cpp +++ b/llvm/utils/TableGen/DecoderEmitter.cpp @@ -2261,7 +2261,8 @@ static void insertBits(InsnType &field, InsnType bits, unsigned startBit, // emitDecodeInstruction - Emit the templated helper function // decodeInstruction(). static void emitDecodeInstruction(formatted_raw_ostream &OS, bool IsVarLenInst, - unsigned OpcodeMask) { + unsigned OpcodeMask, + StringRef SpecializedInsnType) { const bool HasTryDecode = OpcodeMask & ((1 << MCD::OPC_TryDecode) | (1 << MCD::OPC_TryDecodeOrFail)); const bool HasCheckPredicate = @@ -2269,6 +2270,14 @@ static void emitDecodeInstruction(formatted_raw_ostream &OS, bool IsVarLenInst, ((1 << MCD::OPC_CheckPredicate) | (1 << MCD::OPC_CheckPredicateOrFail)); const bool HasSoftFail = OpcodeMask & (1 << MCD::OPC_SoftFail); + auto emitTemplate = [&OS, SpecializedInsnType] { + if (SpecializedInsnType.empty()) + OS << "template \n"; + }; + + StringRef InsnType = + SpecializedInsnType.empty() ? "InsnType" : SpecializedInsnType; + OS << R"( static unsigned decodeNumToSkip(const uint8_t *&Ptr) { unsigned NumToSkip = *Ptr++; @@ -2277,11 +2286,13 @@ static unsigned decodeNumToSkip(const uint8_t *&Ptr) { if (getNumToSkipInBytes() == 3) OS << " NumToSkip |= (*Ptr++) << 16;\n"; OS << R"( return NumToSkip; -} +})"; -template -static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], MCInst &MI, - InsnType insn, uint64_t Address, + emitTemplate(); + OS << R"( +static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], MCInst &MI, )"; + OS << InsnType << " insn,\n"; + OS << R"( uint64_t Address, const MCDisassembler *DisAsm, const MCSubtargetInfo &STI)"; if (IsVarLenInst) { @@ -2802,7 +2813,11 @@ namespace { emitPredicateFunction(OS, TableInfo.Predicates, indent(0)); // Emit the main entry point for the decoder, decodeInstruction(). - emitDecodeInstruction(OS, IsVarLenInst, OpcodeMask); + // Generate non-templated code if exactly one InsnCPPType was specified. + StringRef SpecializedInsnType = + NonTemplatedInsnTypes.size() == 1 ? NonTemplatedInsnTypes[0].CPPType : ""; + + emitDecodeInstruction(OS, IsVarLenInst, OpcodeMask, SpecializedInsnType); OS << "\n} // namespace\n"; } From 1ecd40edc67b7222fa2a45b12a005cef94888086 Mon Sep 17 00:00:00 2001 From: Rahul Joshi Date: Thu, 3 Jul 2025 17:00:22 -0700 Subject: [PATCH 4/5] Full specialization --- llvm/include/llvm/Target/Target.td | 37 +-- llvm/lib/Target/AArch64/AArch64.td | 6 +- llvm/lib/Target/AMDGPU/AMDGPU.td | 7 + .../Disassembler/AMDGPUDisassembler.cpp | 2 +- .../M68k/Disassembler/M68kDisassembler.cpp | 4 +- llvm/lib/Target/RISCV/RISCV.td | 4 - llvm/test/TableGen/DecoderEmitterFnTable.td | 10 +- llvm/test/TableGen/VarLenDecoder.td | 12 +- llvm/test/TableGen/trydecode-emission.td | 20 +- llvm/utils/TableGen/DecoderEmitter.cpp | 295 ++++++++++++------ 10 files changed, 243 insertions(+), 154 deletions(-) diff --git a/llvm/include/llvm/Target/Target.td b/llvm/include/llvm/Target/Target.td index e2e711baaede2..643441bec4268 100644 --- a/llvm/include/llvm/Target/Target.td +++ b/llvm/include/llvm/Target/Target.td @@ -1137,6 +1137,15 @@ class OptionalDefOperand let MIOperandInfo = OpTypes; } +// InstrDecoderOption - This class is used to provide some options to the +// TableGen DecoderEmitter backend. +class InstrDecoderOption bws> { + string CPPType = ty; // C++ type for generating non-templated code. + list 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 InsnCPPTypes = []; - list> 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 DecoderOptions = []; } // Standard Pseudo Instructions. diff --git a/llvm/lib/Target/AArch64/AArch64.td b/llvm/lib/Target/AArch64/AArch64.td index 670027d59acde..25cdcae4e41de 100644 --- a/llvm/lib/Target/AArch64/AArch64.td +++ b/llvm/lib/Target/AArch64/AArch64.td @@ -40,11 +40,7 @@ include "AArch64SchedPredExynos.td" include "AArch64SchedPredNeoverse.td" include "AArch64Combine.td" -def AArch64InstrInfo : InstrInfo { - // Opt-in into non-templated code for instruction decoder. - let InsnCPPTypes = ["uint32_t"]; - let InsnBitwidths = [[32]]; -} +def AArch64InstrInfo : InstrInfo; //===----------------------------------------------------------------------===// // Named operands for MRS/MSR/TLBI/... diff --git a/llvm/lib/Target/AMDGPU/AMDGPU.td b/llvm/lib/Target/AMDGPU/AMDGPU.td index 1a1c32fba9d18..0ce66f7b88cb1 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPU.td +++ b/llvm/lib/Target/AMDGPU/AMDGPU.td @@ -1973,6 +1973,13 @@ def FeatureISAVersion12_Generic: FeatureSet< def AMDGPUInstrInfo : InstrInfo { let guessInstructionProperties = 1; + + // Opt-in into non-templated code for instruction decoder. + let DecoderOptions = [ + InstrDecoderOption<"uint32_t", [32]>, + InstrDecoderOption<"uint64_t", [64]>, + InstrDecoderOption<"DecoderUInt128", [96, 128]>, + ]; } def AMDGPUAsmParser : AsmParser { diff --git a/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.cpp b/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.cpp index 59c72fcbff18a..cd582de176c25 100644 --- a/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.cpp +++ b/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.cpp @@ -591,7 +591,7 @@ DecodeStatus AMDGPUDisassembler::getInstruction(MCInst &MI, uint64_t &Size, // Try to decode DPP and SDWA first to solve conflict with VOP1 and VOP2 // encodings - if (isGFX11Plus() && Bytes.size() >= 12 ) { + if (isGFX11Plus() && Bytes.size() >= 12) { DecoderUInt128 DecW = eat12Bytes(Bytes); if (isGFX11() && diff --git a/llvm/lib/Target/M68k/Disassembler/M68kDisassembler.cpp b/llvm/lib/Target/M68k/Disassembler/M68kDisassembler.cpp index 4ec18fe6bf544..ee453cfc0924e 100644 --- a/llvm/lib/Target/M68k/Disassembler/M68kDisassembler.cpp +++ b/llvm/lib/Target/M68k/Disassembler/M68kDisassembler.cpp @@ -111,13 +111,13 @@ static DecodeStatus DecodeFPCSCRegisterClass(MCInst &Inst, uint64_t RegNo, } #define DecodeFPICRegisterClass DecodeFPCSCRegisterClass -static DecodeStatus DecodeCCRCRegisterClass(MCInst &Inst, APInt &Insn, +static DecodeStatus DecodeCCRCRegisterClass(MCInst &Inst, const APInt &Insn, uint64_t Address, const void *Decoder) { llvm_unreachable("unimplemented"); } -static DecodeStatus DecodeSRCRegisterClass(MCInst &Inst, APInt &Insn, +static DecodeStatus DecodeSRCRegisterClass(MCInst &Inst, const APInt &Insn, uint64_t Address, const void *Decoder) { llvm_unreachable("unimplemented"); diff --git a/llvm/lib/Target/RISCV/RISCV.td b/llvm/lib/Target/RISCV/RISCV.td index b3ce392d27a17..b24d8637cb27f 100644 --- a/llvm/lib/Target/RISCV/RISCV.td +++ b/llvm/lib/Target/RISCV/RISCV.td @@ -85,10 +85,6 @@ include "RISCVPfmCounters.td" def RISCVInstrInfo : InstrInfo { let guessInstructionProperties = 0; - - // Opt-in into non-templated code for instruction decoder. - let InsnCPPTypes = ["uint64_t"]; - let InsnBitwidths = [[16, 32, 48]]; } def RISCVAsmParser : AsmParser { diff --git a/llvm/test/TableGen/DecoderEmitterFnTable.td b/llvm/test/TableGen/DecoderEmitterFnTable.td index 7bed18c19a513..837ec3bdc5c84 100644 --- a/llvm/test/TableGen/DecoderEmitterFnTable.td +++ b/llvm/test/TableGen/DecoderEmitterFnTable.td @@ -71,11 +71,11 @@ def Inst3 : TestInstruction { let AsmString = "Inst3"; } -// CHECK-LABEL: DecodeStatus decodeFn0(DecodeStatus S, InsnType insn, MCInst &MI, uint64_t Address, const MCDisassembler *Decoder, bool &DecodeComplete) -// CHECK-LABEL: DecodeStatus decodeFn1(DecodeStatus S, InsnType insn, MCInst &MI, uint64_t Address, const MCDisassembler *Decoder, bool &DecodeComplete) -// CHECK-LABEL: DecodeStatus decodeFn2(DecodeStatus S, InsnType insn, MCInst &MI, uint64_t Address, const MCDisassembler *Decoder, bool &DecodeComplete) -// CHECK-LABEL: DecodeStatus decodeFn3(DecodeStatus S, InsnType insn, MCInst &MI, uint64_t Address, const MCDisassembler *Decoder, bool &DecodeComplete) -// CHECK-LABEL: decodeToMCInst(unsigned Idx, DecodeStatus S, InsnType insn, MCInst &MI, uint64_t Address, const MCDisassembler *Decoder, bool &DecodeComplete) +// CHECK-LABEL: DecodeStatus decodeFn0(DecodeStatus S, const InsnType &insn, MCInst &MI, uint64_t Address, const MCDisassembler *Decoder, bool &DecodeComplete) +// CHECK-LABEL: DecodeStatus decodeFn1(DecodeStatus S, const InsnType &insn, MCInst &MI, uint64_t Address, const MCDisassembler *Decoder, bool &DecodeComplete) +// CHECK-LABEL: DecodeStatus decodeFn2(DecodeStatus S, const InsnType &insn, MCInst &MI, uint64_t Address, const MCDisassembler *Decoder, bool &DecodeComplete) +// CHECK-LABEL: DecodeStatus decodeFn3(DecodeStatus S, const InsnType &insn, MCInst &MI, uint64_t Address, const MCDisassembler *Decoder, bool &DecodeComplete) +// CHECK-LABEL: decodeToMCInst(unsigned Idx, DecodeStatus S, const InsnType &insn, MCInst &MI, uint64_t Address, const MCDisassembler *Decoder, bool &DecodeComplete) // CHECK: static constexpr DecodeFnTy decodeFnTable[] // CHECK-NEXT: decodeFn0, // CHECK-NEXT: decodeFn1, diff --git a/llvm/test/TableGen/VarLenDecoder.td b/llvm/test/TableGen/VarLenDecoder.td index 2359bd2c15145..d438e64264cbd 100644 --- a/llvm/test/TableGen/VarLenDecoder.td +++ b/llvm/test/TableGen/VarLenDecoder.td @@ -47,6 +47,12 @@ def FOO32 : MyVarInst { ); } +// 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 { // CHECK-NEXT: MI.addOperand(MCOperand::createImm(tmp)); // CHECK-NEXT: return S; -// Instruction length table -// CHECK-LABEL: InstrLenTable -// CHECK: 27, -// CHECK-NEXT: 43, -// CHECK-NEXT: }; - // CHECK-LABEL: decodeInstruction // CHECK-LABEL: case MCD::OPC_ExtractField: { // CHECK: makeUp(insn, Start + Len); diff --git a/llvm/test/TableGen/trydecode-emission.td b/llvm/test/TableGen/trydecode-emission.td index c3178dd71cf4b..8e427c8a7107b 100644 --- a/llvm/test/TableGen/trydecode-emission.td +++ b/llvm/test/TableGen/trydecode-emission.td @@ -34,6 +34,17 @@ def InstB : TestInstruction { let hasCompleteDecoder = 0; } +// CHECK-LABEL: decodeNumToSkip +// CHECK-NEXT: unsigned NumToSkip = *Ptr++; +// CHECK-NEXT: NumToSkip |= (*Ptr++) << 8; +// CHECK-NEXT: return NumToSkip; + +// CHECK-LARGE-LABEL: decodeNumToSkip +// CHECK-LARGE-NEXT: unsigned NumToSkip = *Ptr++; +// CHECK-LARGE-NEXT: NumToSkip |= (*Ptr++) << 8; +// CHECK-LARGE-NEXT: NumToSkip |= (*Ptr++) << 16; +// CHECK-LARGE-NEXT: return NumToSkip; + // CHECK: /* 0 */ MCD::OPC_ExtractField, 4, 4, // Inst{7-4} ... // CHECK-NEXT: /* 3 */ MCD::OPC_FilterValueOrFail, 0, // CHECK-NEXT: /* 5 */ MCD::OPC_CheckField, 2, 2, 0, 6, 0, // Skip to: 17 @@ -43,10 +54,6 @@ def InstB : TestInstruction { // CHECK: if (!Check(S, DecodeInstB(MI, insn, Address, Decoder))) { DecodeComplete = false; return MCDisassembler::Fail; } -// CHECK: unsigned NumToSkip = *Ptr++; -// CHECK-NEXT: NumToSkip |= (*Ptr++) << 8; -// CHECK-NEXT: return NumToSkip; - // CHECK-LARGE: /* 0 */ MCD::OPC_ExtractField, 4, 4, // Inst{7-4} ... // CHECK-LARGE-NEXT: /* 3 */ MCD::OPC_FilterValueOrFail, 0, // CHECK-LARGE-NEXT: /* 5 */ MCD::OPC_CheckField, 2, 2, 0, 7, 0, 0, // Skip to: 19 @@ -55,8 +62,3 @@ def InstB : TestInstruction { // CHECK-LARGE-NEXT: /* 23 */ MCD::OPC_Fail, // CHECK-LARGE: if (!Check(S, DecodeInstB(MI, insn, Address, Decoder))) { DecodeComplete = false; return MCDisassembler::Fail; } - -// CHECK-LARGE: unsigned NumToSkip = *Ptr++; -// CHECK-LARGE-NEXT: NumToSkip |= (*Ptr++) << 8; -// CHECK-LARGE-NEXT: NumToSkip |= (*Ptr++) << 16; -// CHECK-LARGE-NEXT: return NumToSkip; diff --git a/llvm/utils/TableGen/DecoderEmitter.cpp b/llvm/utils/TableGen/DecoderEmitter.cpp index 00123c62b6724..d7c37f112cd44 100644 --- a/llvm/utils/TableGen/DecoderEmitter.cpp +++ b/llvm/utils/TableGen/DecoderEmitter.cpp @@ -223,6 +223,9 @@ using BitwidthSet = SmallSet; struct NonTemplatedInsnType { StringRef CPPType; BitwidthSet Bitwidths; + + NonTemplatedInsnType(StringRef CPPType, BitwidthSet Bitwidths) + : CPPType(CPPType), Bitwidths(std::move(Bitwidths)) {} }; class DecoderEmitter { @@ -1077,21 +1080,25 @@ void DecoderEmitter::emitPredicateFunction(formatted_raw_ostream &OS, OS << Indent << "}\n\n"; } +static void emitTemplate(formatted_raw_ostream &OS, + StringRef SpecializedInsnType) { + if (SpecializedInsnType.empty()) + OS << "template \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 \n"; - }; - - StringRef InsnType = - SpecializedInsnType.empty() ? "InsnType" : SpecializedInsnType; - // The decoder function is just a big switch statement or a table of function // pointers based on the input decoder index. + StringRef InsnType = getInsnType(SpecializedInsnType); + // TODO: When InsnType is large, using uint64_t limits all fields to 64 bits // It would be better for emitBinaryParser to use a 64-bit tmp whenever // possible but fall back to an InsnType-sized tmp for truly large fields. @@ -1100,14 +1107,14 @@ void DecoderEmitter::emitDecoderFunction(formatted_raw_ostream &OS, "uint64_t>;\n", InsnType); auto DecodeParams = - formatv("DecodeStatus S, {} insn, MCInst &MI, uint64_t Address, const " - "MCDisassembler *Decoder, bool &DecodeComplete", + formatv("DecodeStatus S, const {} &insn, MCInst &MI, uint64_t Address, " + "const MCDisassembler *Decoder, bool &DecodeComplete", InsnType); if (UseFnTableInDecodeToMCInst) { // Emit a function for each case first. for (const auto &[Index, Decoder] : enumerate(Decoders)) { - emitTemplate(); + emitTemplate(OS, SpecializedInsnType); OS << Indent << "DecodeStatus decodeFn" << Index << "(" << DecodeParams << ") {\n"; Indent += 2; @@ -1121,7 +1128,7 @@ void DecoderEmitter::emitDecoderFunction(formatted_raw_ostream &OS, } OS << Indent << "// Handling " << Decoders.size() << " cases.\n"; - emitTemplate(); + emitTemplate(OS, SpecializedInsnType); OS << Indent << "static DecodeStatus decodeToMCInst(unsigned Idx, " << DecodeParams << ") {\n"; Indent += 2; @@ -2196,12 +2203,19 @@ populateInstruction(const CodeGenTarget &Target, const Record &EncodingDef, return Bits.getNumBits(); } +static bool isKnownIntegralType(StringRef InsnType) { + static constexpr StringLiteral KnownIntegralTypes[] = {"uint16_t", "uint32_t", + "uint64_t"}; + return llvm::is_contained(KnownIntegralTypes, InsnType); +} + // emitFieldFromInstruction - Emit the templated helper function // fieldFromInstruction(). // On Windows we make sure that this function is not inlined when // using the VS compiler. It has a bug which causes the function // to be optimized out in some circumstances. See llvm.org/pr38292 -static void emitFieldFromInstruction(formatted_raw_ostream &OS) { +static void emitFieldFromInstruction(formatted_raw_ostream &OS, + StringRef SpecializedInsnType) { OS << R"( // Helper functions for extracting fields from encoded instructions. // InsnType must either be integral or an APInt-like object that must: @@ -2212,54 +2226,122 @@ static void emitFieldFromInstruction(formatted_raw_ostream &OS) { // * Support the ~, &, ==, and != operators with other objects of the same type // * Support the != and bitwise & with uint64_t // * Support put (<<) to raw_ostream& -template + +// 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::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::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 -static std::enable_if_t::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::value, uint64_t>\n", + InsnType); + } else { + OS << formatv("static uint64_t "); + } + + OS << formatv(R"(fieldFromInstruction(const {0} &insn, unsigned startBit, + unsigned numBits) {{ return insn.extractBitsAsZExtValue(numBits, startBit); } -)"; +)", + InsnType); + } // if (GenerateTemplatedForm || !IsIntegralType) + OS << "#undef DEC_EMIT_NO_INLINE\n"; } // emitInsertBits - Emit the templated helper function insertBits(). -static void emitInsertBits(formatted_raw_ostream &OS) { +static void emitInsertBits(formatted_raw_ostream &OS, + StringRef SpecializedInsnType) { + bool GenerateTemplatedForm = SpecializedInsnType.empty(); + StringRef InsnType = getInsnType(SpecializedInsnType); + bool IsIntegralType = isKnownIntegralType(InsnType); + + auto FuncDecl = formatv(R"([[maybe_unused]] +static void insertBits({0} &field, {0} bits, unsigned startBit, + unsigned numBits) {{)", + InsnType); + OS << R"( // Helper function for inserting bits extracted from an encoded instruction into // a field. -template -static void insertBits(InsnType &field, InsnType bits, unsigned startBit, - unsigned numBits) { - if constexpr (std::is_integral::value) { +)"; + if (GenerateTemplatedForm) { + emitTemplate(OS, SpecializedInsnType); + OS << FuncDecl; + OS << formatv(R"( + if constexpr (std::is_integral<{0}>::value) {{ assert(startBit + numBits <= sizeof field * 8); (void)numBits; - field |= (InsnType)bits << startBit; - } else { + field |= ({0})bits << startBit; + } else {{ field.insertBits(bits, startBit, numBits); } } +)", + InsnType); + } else if (IsIntegralType) { + OS << FuncDecl; + OS << formatv(R"( + assert(startBit + numBits <= sizeof field * 8); + (void)numBits; + field |= ({0})bits << startBit; +} +)", + InsnType); + } else { + // Code for !IsIntegralType + OS << FuncDecl; + OS << R"( + field.insertBits(bits, startBit, numBits); +} )"; + } + OS << '\n'; } -// emitDecodeInstruction - Emit the templated helper function -// decodeInstruction(). +// emitDecodeInstruction - Emit the entry function function decodeInstruction(). static void emitDecodeInstruction(formatted_raw_ostream &OS, bool IsVarLenInst, unsigned OpcodeMask, StringRef SpecializedInsnType) { @@ -2270,29 +2352,19 @@ static void emitDecodeInstruction(formatted_raw_ostream &OS, bool IsVarLenInst, ((1 << MCD::OPC_CheckPredicate) | (1 << MCD::OPC_CheckPredicateOrFail)); const bool HasSoftFail = OpcodeMask & (1 << MCD::OPC_SoftFail); - auto emitTemplate = [&OS, SpecializedInsnType] { - if (SpecializedInsnType.empty()) - OS << "template \n"; - }; - - StringRef InsnType = - SpecializedInsnType.empty() ? "InsnType" : SpecializedInsnType; + StringRef InsnType = getInsnType(SpecializedInsnType); - OS << R"( -static unsigned decodeNumToSkip(const uint8_t *&Ptr) { - unsigned NumToSkip = *Ptr++; - NumToSkip |= (*Ptr++) << 8; -)"; - if (getNumToSkipInBytes() == 3) - OS << " NumToSkip |= (*Ptr++) << 16;\n"; - OS << R"( return NumToSkip; -})"; - - emitTemplate(); + emitTemplate(OS, SpecializedInsnType); OS << R"( static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], MCInst &MI, )"; - OS << InsnType << " insn,\n"; - OS << R"( uint64_t Address, + // For variable length instructions, use a non-const reference to match the + // signature of the `makeUp` function passed in. + if (IsVarLenInst) + OS << InsnType << " &insn,"; + else + OS << "const " << InsnType << " &insn,"; + OS << R"( + uint64_t Address, const MCDisassembler *DisAsm, const MCSubtargetInfo &STI)"; if (IsVarLenInst) { @@ -2496,16 +2568,31 @@ static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], MCInst &MI, ) )"; } +static void emitCommonFunctions(formatted_raw_ostream &OS) { + OS << R"( // Helper to propagate SoftFail status. Returns false if the status is Fail; // callers are expected to early-exit in that condition. (Note, the '&' operator // is correct to propagate the values of this enum; see comment on 'enum // DecodeStatus'.) -static void emitCheck(formatted_raw_ostream &OS) { - OS << R"( static bool Check(DecodeStatus &Out, DecodeStatus In) { Out = static_cast(Out & In); return Out != MCDisassembler::Fail; } +)"; + + OS << R"( +// Helper to decode the `NumToSkip` value encoded in the decoder table. +static unsigned decodeNumToSkip(const uint8_t *&Ptr) { + unsigned NumToSkip = *Ptr++; + NumToSkip |= (*Ptr++) << 8; +)"; + if (getNumToSkipInBytes() == 3) + OS << " NumToSkip |= (*Ptr++) << 16;\n"; + OS << R"( return NumToSkip; +} + +// Forward declaration. +[[maybe_unused]] static bool checkDecoderPredicate(unsigned Idx, const FeatureBitset &Bits); )"; } @@ -2575,39 +2662,36 @@ DecoderEmitter::parseNonTemplatedInsnTypes(BitwidthSet &InstrBitwidths) { SmallVector Parsed; const Record *InstructionSet = Target.getInstructionSet(); - std::vector 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 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(BWL); - if (!BitwidthList || BitwidthList->empty()) + + const ListInit *BWL = Option->getValueAsListInit("Bitwidths"); + if (!BWL || BWL->empty()) PrintFatalError(BitwidthsLoc, - "No bitwidths specified for InsnCPPType : " + CPPType); + "No bitwidths specified for CPPType : " + CPPType); - for (int64_t Bitwidth : BitwidthList->getAsListOfInts()) { + BitwidthSet Bitwidths; + for (int64_t Bitwidth : BWL->getAsListOfInts()) { if (!OptionBitwidths.insert(Bitwidth).second) PrintFatalError(BitwidthsLoc, "Bitwidth " + Twine(Bitwidth) + " already specified."); @@ -2618,7 +2702,7 @@ DecoderEmitter::parseNonTemplatedInsnTypes(BitwidthSet &InstrBitwidths) { InstrBitwidths.erase(Bitwidth); Bitwidths.insert(Bitwidth); } - Parsed.emplace_back(NonTemplatedInsnType{CPPType, Bitwidths}); + Parsed.emplace_back(CPPType, Bitwidths); } if (!InstrBitwidths.empty()) { @@ -2648,9 +2732,7 @@ void DecoderEmitter::run(raw_ostream &o) { namespace { )"; - emitFieldFromInstruction(OS); - emitInsertBits(OS); - emitCheck(OS); + emitCommonFunctions(OS); Target.reverseBitsForLittleEndianEncoding(); @@ -2700,7 +2782,7 @@ namespace { OpcMap; std::map> Operands; std::vector InstrLen; - bool IsVarLenInst = Target.hasVariableLengthEncodings(); + const bool IsVarLenInst = Target.hasVariableLengthEncodings(); unsigned MaxInstLen = 0; for (const auto &[NEI, NumberedEncoding] : enumerate(NumberedEncodings)) { @@ -2743,6 +2825,12 @@ namespace { } } + // For variable instruction, we emit a instruction length table + // to let the decoder know how long the instructions are. + // You can see example usage in M68k's disassembler. + if (IsVarLenInst) + emitInstrLenTable(OS, InstrLen); + // Collect all allowed Bitwidths for instructions. BitwidthSet InstrBitwidths; for (const auto &[NSAndByteSize, _] : OpcMap) { @@ -2753,10 +2841,21 @@ namespace { parseNonTemplatedInsnTypes(InstrBitwidths); DecoderTableInfo TableInfo; - unsigned OpcodeMask = 0; + bool HasCheckPredicate = false; for (const auto &[NTType, NTBitwidths] : NonTemplatedInsnTypes) { // Reset the Decoders for each non-templated type. TableInfo.Decoders.clear(); + unsigned OpcodeMask = 0; + + if (!NTType.empty()) { + OS << "// ------------------------------------------------------------\n"; + OS << "// Decoder tables and functions for bitwidths: "; + interleaveComma(NTBitwidths, OS); + OS << "\n// Using InsnType = " << NTType << '\n'; + } + + emitFieldFromInstruction(OS, NTType); + emitInsertBits(OS, NTType); for (const auto &[NSAndByteSize, EncodingIDs] : OpcMap) { const std::string &DecoderNamespace = NSAndByteSize.first; @@ -2796,29 +2895,17 @@ namespace { // Emit the decoder function for this BitWidth. emitDecoderFunction(OS, TableInfo.Decoders, NTType, indent(0)); - } - // For variable instruction, we emit a instruction length table - // to let the decoder know how long the instructions are. - // You can see example usage in M68k's disassembler. - if (IsVarLenInst) - emitInstrLenTable(OS, InstrLen); + HasCheckPredicate |= OpcodeMask & ((1 << MCD::OPC_CheckPredicate) | + (1 << MCD::OPC_CheckPredicateOrFail)); - const bool HasCheckPredicate = - OpcodeMask & - ((1 << MCD::OPC_CheckPredicate) | (1 << MCD::OPC_CheckPredicateOrFail)); + emitDecodeInstruction(OS, IsVarLenInst, OpcodeMask, NTType); + } // Emit the predicate function. if (HasCheckPredicate) emitPredicateFunction(OS, TableInfo.Predicates, indent(0)); - // Emit the main entry point for the decoder, decodeInstruction(). - // Generate non-templated code if exactly one InsnCPPType was specified. - StringRef SpecializedInsnType = - NonTemplatedInsnTypes.size() == 1 ? NonTemplatedInsnTypes[0].CPPType : ""; - - emitDecodeInstruction(OS, IsVarLenInst, OpcodeMask, SpecializedInsnType); - OS << "\n} // namespace\n"; } From 627a4435ea53bdebc6cf140106c425a84336b425 Mon Sep 17 00:00:00 2001 From: Rahul Joshi Date: Thu, 3 Jul 2025 21:00:01 -0700 Subject: [PATCH 5/5] Rename NonTemplatedInsnType to a more generic DecoderOption --- llvm/utils/TableGen/DecoderEmitter.cpp | 43 +++++++++++++------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/llvm/utils/TableGen/DecoderEmitter.cpp b/llvm/utils/TableGen/DecoderEmitter.cpp index d7c37f112cd44..10f72ffa5b172 100644 --- a/llvm/utils/TableGen/DecoderEmitter.cpp +++ b/llvm/utils/TableGen/DecoderEmitter.cpp @@ -217,14 +217,13 @@ struct EncodingIDAndOpcode { using EncodingIDsVec = std::vector; using NamespacesHwModesMap = std::map>; -// Result of parsing the `InsnCPPTypes` and `InstBitwidths` fields in the Target -// instruction set. +// Result of parsing the `DecodeOptions` field in the Target instruction set. using BitwidthSet = SmallSet; -struct NonTemplatedInsnType { +struct DecoderOption { StringRef CPPType; BitwidthSet Bitwidths; - NonTemplatedInsnType(StringRef CPPType, BitwidthSet Bitwidths) + DecoderOption(StringRef CPPType, BitwidthSet Bitwidths) : CPPType(CPPType), Bitwidths(std::move(Bitwidths)) {} }; @@ -252,8 +251,8 @@ class DecoderEmitter { void run(raw_ostream &o); private: - SmallVector - parseNonTemplatedInsnTypes(BitwidthSet &InstrBitwidths); + SmallVector parseDecoderOptions(BitwidthSet &InstrBitwidths); + CodeGenTarget Target; public: @@ -2657,9 +2656,9 @@ handleHwModesUnrelatedEncodings(const CodeGenInstruction *Instr, break; } } -SmallVector -DecoderEmitter::parseNonTemplatedInsnTypes(BitwidthSet &InstrBitwidths) { - SmallVector Parsed; +SmallVector +DecoderEmitter::parseDecoderOptions(BitwidthSet &InstrBitwidths) { + SmallVector Parsed; const Record *InstructionSet = Target.getInstructionSet(); std::vector DecoderOptions = @@ -2683,7 +2682,7 @@ DecoderEmitter::parseNonTemplatedInsnTypes(BitwidthSet &InstrBitwidths) { StringRef CPPType = Option->getValueAsString("CPPType"); if (CPPType.empty()) PrintFatalError(CPPTypesLoc, - "CPP Type cannot be empty in `InsnCPPTypes`"); + "CPP Type cannot be empty in DecoderOptions"); const ListInit *BWL = Option->getValueAsListInit("Bitwidths"); if (!BWL || BWL->empty()) @@ -2710,7 +2709,7 @@ DecoderEmitter::parseNonTemplatedInsnTypes(BitwidthSet &InstrBitwidths) { PrintFatalError([&InstrBitwidths](raw_ostream &OS) { OS << "Bitwidth(s) "; interleaveComma(InstrBitwidths, OS); - OS << " missing in `InsnBitwidths`"; + OS << " missing in DecoderOptions"; }); } return Parsed; @@ -2837,25 +2836,25 @@ namespace { const unsigned Bitwidth = 8 * NSAndByteSize.second; InstrBitwidths.insert(Bitwidth); } - SmallVector NonTemplatedInsnTypes = - parseNonTemplatedInsnTypes(InstrBitwidths); + SmallVector DecoderOptions = + parseDecoderOptions(InstrBitwidths); DecoderTableInfo TableInfo; bool HasCheckPredicate = false; - for (const auto &[NTType, NTBitwidths] : NonTemplatedInsnTypes) { + for (const auto &[CPPType, Bitwidths] : DecoderOptions) { // 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'; + interleaveComma(Bitwidths, OS); + OS << "\n// Using InsnType = " << CPPType << '\n'; } - emitFieldFromInstruction(OS, NTType); - emitInsertBits(OS, NTType); + emitFieldFromInstruction(OS, CPPType); + emitInsertBits(OS, CPPType); for (const auto &[NSAndByteSize, EncodingIDs] : OpcMap) { const std::string &DecoderNamespace = NSAndByteSize.first; @@ -2864,7 +2863,7 @@ namespace { // Only handle instruction of the non-templated bitwidth size when // non-templated bitwidth option is enabled. - if (!NTBitwidths.empty() && !NTBitwidths.contains(InstrBitwidth)) + if (!Bitwidths.empty() && !Bitwidths.contains(InstrBitwidth)) continue; // Emit the decoder for this namespace+width combination. @@ -2894,12 +2893,12 @@ namespace { } // Emit the decoder function for this BitWidth. - emitDecoderFunction(OS, TableInfo.Decoders, NTType, indent(0)); + emitDecoderFunction(OS, TableInfo.Decoders, CPPType, indent(0)); HasCheckPredicate |= OpcodeMask & ((1 << MCD::OPC_CheckPredicate) | (1 << MCD::OPC_CheckPredicateOrFail)); - emitDecodeInstruction(OS, IsVarLenInst, OpcodeMask, NTType); + emitDecodeInstruction(OS, IsVarLenInst, OpcodeMask, CPPType); } // Emit the predicate function.