Skip to content

[LLVM][MC] Introduce OrFail variants of MCD ops #138614

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

jurahul
Copy link
Contributor

@jurahul jurahul commented May 5, 2025

Introduce OrFail variants for all MCD Decoder Ops that have NumToSKip encoded with them. This is intended to capture the common case of jumps to the end of the decoder table which has a OP_Fail at the end. Using the OrFail variants of these ops avoid encoding the NumToSkip jump offset for these cases, resulting in a reduction in the size of the decoder tables (from 5 - 17%). Additionally, for the AArch64 target, the table size reduces enough to switch to using 2-byte NumToSkip encoding instead of existing 3-bytes, resulting in a net 30% reduction in the size of the decoder table.

The total reduction in the size of the decoder tables for different targets is as follows (computed using the following command: for i in *.inc; do echo -n ``basename $i: ``; grep "MCD::OPC_Fail," $i | awk '{sum += $2} END { print sum}'; done)

Target         Old Size   New Size   % Reduction
================================================
AArch64           153268     106987       30.20
AMDGPU            412056     340856       17.28
ARC                 5061       4605        9.01
ARM                73831      60847       17.59
AVR                 1306       1158       11.33
BPF                 1927       1795        6.85
CSKY                8692       6922       20.36
Hexagon            41965      34759       17.17
Lanai                982        924        5.91
LoongArch          21629      20035        7.37
M68k               13461      11689       13.16
MSP430              3716       3384        8.93
Mips               31415      25771       17.97
PPC                28931      24771       14.38
RISCV              34800      28352       18.53
Sparc               7432       6236       16.09
SystemZ            32248      29716        7.85
VE                 42873      36923       13.88
XCore               2316       2196        5.18
Xtensa              3443       2793       18.88

@jurahul jurahul force-pushed the decoder_emitter_orfail_ops branch from 848d288 to fb64757 Compare May 7, 2025 16:55
@jurahul jurahul force-pushed the decoder_emitter_orfail_ops branch from fb64757 to d9ec6d3 Compare May 27, 2025 18:00
@jurahul jurahul force-pushed the decoder_emitter_orfail_ops branch from d9ec6d3 to e99f469 Compare May 27, 2025 20:00
@jurahul jurahul marked this pull request as ready for review May 28, 2025 02:21
@llvmbot llvmbot added backend:AArch64 tablegen bazel "Peripheral" support tier build system: utils/bazel labels May 28, 2025
@jurahul jurahul requested review from topperc and s-barannikov and removed request for keith, rupprecht and aaronmondal May 28, 2025 02:21
@llvmbot
Copy link
Member

llvmbot commented May 28, 2025

@llvm/pr-subscribers-tablegen

@llvm/pr-subscribers-backend-aarch64

Author: Rahul Joshi (jurahul)

Changes

Introduce OrFail variants of a subset of MCD Decoder Ops. This is intended to capture the common case of jumps to the end of the decoder table which has a OP_Fail at the end. Using these OrFail variants of these ops avoid encoding the NumToSkip jump offset for these cases, resulting in a reduction in the size of the decoder tables (from 5 - 17%). Additionally, for the AArch64 target, the table size reduces enough to switch to using 2-byte NumToSkip encoding instead of existing 3-bytes, resulting in a net 30% reduction in the size of the decoder table.

The total reduction in the size of the decoder tables for different targets is as follows (computed using the following command: for i in *.inc; do echo -n ``basename $i: ``; grep "MCD::OPC_Fail," $i | awk '{sum += $2} END { print sum}'; done

Target         Old Size   New Size   % Reduction
================================================
AArch64           153268     106987       30.20
AMDGPU            412056     340856       17.28
ARC                 5061       4605        9.01
ARM                73831      60847       17.59
AVR                 1306       1158       11.33
BPF                 1927       1795        6.85
CSKY                8692       6922       20.36
Hexagon            41965      34759       17.17
Lanai                982        924        5.91
LoongArch          21629      20035        7.37
M68k               13461      11689       13.16
MSP430              3716       3384        8.93
Mips               31415      25771       17.97
PPC                28931      24771       14.38
RISCV              34800      28352       18.53
Sparc               7432       6236       16.09
SystemZ            32248      29716        7.85
VE                 42873      36923       13.88
XCore               2316       2196        5.18
Xtensa              3443       2793       18.88

Patch is 34.63 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/138614.diff

9 Files Affected:

  • (modified) llvm/include/llvm/MC/MCDecoderOps.h (+19-14)
  • (modified) llvm/lib/Target/AArch64/CMakeLists.txt (+1-2)
  • (modified) llvm/test/TableGen/VarLenDecoder.td (+11-10)
  • (modified) llvm/test/TableGen/trydecode-emission.td (+10-10)
  • (modified) llvm/test/TableGen/trydecode-emission2.td (+16-16)
  • (modified) llvm/test/TableGen/trydecode-emission3.td (+10-10)
  • (modified) llvm/test/TableGen/trydecode-emission4.td (+10-10)
  • (modified) llvm/utils/TableGen/DecoderEmitter.cpp (+172-81)
  • (modified) utils/bazel/llvm-project-overlay/llvm/BUILD.bazel (-1)
diff --git a/llvm/include/llvm/MC/MCDecoderOps.h b/llvm/include/llvm/MC/MCDecoderOps.h
index 3c0b68101e346..29d62988e888e 100644
--- a/llvm/include/llvm/MC/MCDecoderOps.h
+++ b/llvm/include/llvm/MC/MCDecoderOps.h
@@ -10,24 +10,29 @@
 #ifndef LLVM_MC_MCDECODEROPS_H
 #define LLVM_MC_MCDECODEROPS_H
 
-namespace llvm {
+namespace llvm::MCD {
 
-namespace MCD {
 // Disassembler state machine opcodes.
+// nts_t is either uint16_t or uint24_t based on whether large decoder table is
+// enabled.
 enum DecoderOps {
-  OPC_ExtractField = 1, // OPC_ExtractField(uleb128 Start, uint8_t Len)
-  OPC_FilterValue,      // OPC_FilterValue(uleb128 Val, uint16_t NumToSkip)
-  OPC_CheckField,       // OPC_CheckField(uleb128 Start, uint8_t Len,
-                        //                uleb128 Val, uint16_t NumToSkip)
-  OPC_CheckPredicate,   // OPC_CheckPredicate(uleb128 PIdx, uint16_t NumToSkip)
-  OPC_Decode,           // OPC_Decode(uleb128 Opcode, uleb128 DIdx)
-  OPC_TryDecode,        // OPC_TryDecode(uleb128 Opcode, uleb128 DIdx,
-                        //               uint16_t NumToSkip)
-  OPC_SoftFail,         // OPC_SoftFail(uleb128 PMask, uleb128 NMask)
-  OPC_Fail              // OPC_Fail()
+  OPC_ExtractField = 1,     // OPC_ExtractField(uleb128 Start, uint8_t Len)
+  OPC_FilterValue,          // OPC_FilterValue(uleb128 Val, nts_t NumToSkip)
+  OPC_FilterValueOrFail,    // OPC_FilterValueOrFail(uleb128 Val)
+  OPC_CheckField,           // OPC_CheckField(uleb128 Start, uint8_t Len,
+                            //                uleb128 Val, nts_t NumToSkip)
+  OPC_CheckFieldOrFail,     // OPC_ChecFieldOrFail(uleb128 Start, uint8_t Len,
+                            //                uleb128 Val)
+  OPC_CheckPredicate,       // OPC_CheckPredicate(uleb128 PIdx, nts_t NumToSkip)
+  OPC_CheckPredicateOrFail, // OPC_CheckPredicateOrFail(uleb128 PIdx)
+  OPC_Decode,               // OPC_Decode(uleb128 Opcode, uleb128 DIdx)
+  OPC_TryDecode,            // OPC_TryDecode(uleb128 Opcode, uleb128 DIdx,
+                            //               nts_t NumToSkip)
+  OPC_TryDecodeOrFail,      // OPC_TryDecodeOrFail(uleb128 Opcode, uleb128 DIdx)
+  OPC_SoftFail,             // OPC_SoftFail(uleb128 PMask, uleb128 NMask)
+  OPC_Fail                  // OPC_Fail()
 };
 
-} // namespace MCD
-} // namespace llvm
+} // namespace llvm::MCD
 
 #endif
diff --git a/llvm/lib/Target/AArch64/CMakeLists.txt b/llvm/lib/Target/AArch64/CMakeLists.txt
index 583003f2f46e6..2300e479bc110 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
-              --large-decoder-table)
+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/test/TableGen/VarLenDecoder.td b/llvm/test/TableGen/VarLenDecoder.td
index db7a520533e85..06ff62294a196 100644
--- a/llvm/test/TableGen/VarLenDecoder.td
+++ b/llvm/test/TableGen/VarLenDecoder.td
@@ -47,19 +47,19 @@ def FOO32 : MyVarInst<MemOp32> {
   );
 }
 
-// CHECK-SMALL:      MCD::OPC_ExtractField, 3, 5,  // Inst{7-3} ...
-// CHECK-SMALL-NEXT: MCD::OPC_FilterValue, 8, 4, 0, // Skip to: 11
-// CHECK-SMALL-NEXT: MCD::OPC_Decode, {{[0-9]+}}, {{[0-9]+}}, 0, // Opcode: FOO16
-// CHECK-SMALL-NEXT: MCD::OPC_FilterValue, 9, 4, 0, // Skip to: 19
-// CHECK-SMALL-NEXT: MCD::OPC_Decode, {{[0-9]+}}, {{[0-9]+}}, 1, // Opcode: FOO32
-// CHECK-SMALL-NEXT: MCD::OPC_Fail,
+// 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
+// CHECK-SMALL-NEXT: /* 11 */      MCD::OPC_FilterValueOrFail, 9,
+// CHECK-SMALL-NEXT: /* 13 */      MCD::OPC_Decode, {{[0-9]+}}, {{[0-9]+}}, 1, // Opcode: FOO32
+// CHECK-SMALL-NEXT: /* 17 */      MCD::OPC_Fail,
 
 // CHECK-LARGE:      /* 0 */       MCD::OPC_ExtractField, 3, 5,  // Inst{7-3} ...
 // CHECK-LARGE-NEXT: /* 3 */       MCD::OPC_FilterValue, 8, 4, 0, 0, // Skip to: 12
 // CHECK-LARGE-NEXT: /* 8 */       MCD::OPC_Decode, {{[0-9]+}}, {{[0-9]+}}, 0, // Opcode: FOO16
-// CHECK-LARGE-NEXT: /* 12 */      MCD::OPC_FilterValue, 9, 4, 0, 0, // Skip to: 21
-// CHECK-LARGE-NEXT: /* 17 */      MCD::OPC_Decode, {{[0-9]+}}, {{[0-9]+}}, 1, // Opcode: FOO32
-// CHECK-LARGE-NEXT: /* 21 */      MCD::OPC_Fail,
+// CHECK-LARGE-NEXT: /* 12 */      MCD::OPC_FilterValueOrFail, 9,
+// 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,
@@ -88,7 +88,8 @@ def FOO32 : MyVarInst<MemOp32> {
 // CHECK-LABEL: case MCD::OPC_ExtractField: {
 // CHECK: makeUp(insn, Start + Len);
 
-// CHECK-LABEL: case MCD::OPC_CheckField: {
+// CHECK-LABEL: case MCD::OPC_CheckField:
+// CHECK-NEXT:  case MCD::OPC_CheckFieldOrFail: {
 // CHECK: makeUp(insn, Start + Len);
 
 // CHECK-LABEL: case MCD::OPC_Decode: {
diff --git a/llvm/test/TableGen/trydecode-emission.td b/llvm/test/TableGen/trydecode-emission.td
index db77d94b2aa52..47d47c9c96183 100644
--- a/llvm/test/TableGen/trydecode-emission.td
+++ b/llvm/test/TableGen/trydecode-emission.td
@@ -35,11 +35,11 @@ def InstB : TestInstruction {
 }
 
 // CHECK:      /* 0 */       MCD::OPC_ExtractField, 4, 4,  // Inst{7-4} ...
-// CHECK-NEXT: /* 3 */       MCD::OPC_FilterValue, 0, 16, 0, // Skip to: 23
-// CHECK-NEXT: /* 7 */       MCD::OPC_CheckField, 2, 2, 0, 6, 0, // Skip to: 19
-// CHECK-NEXT: /* 13 */      MCD::OPC_TryDecode, {{[0-9]+}}, {{[0-9]+}}, 0, 0, 0, // Opcode: InstB, skip to: 19
-// CHECK-NEXT: /* 19 */      MCD::OPC_Decode, {{[0-9]+}}, {{[0-9]+}}, 1, // Opcode: InstA
-// CHECK-NEXT: /* 23 */      MCD::OPC_Fail,
+// CHECK-NEXT: /* 3 */       MCD::OPC_FilterValueOrFail, 0,
+// CHECK-NEXT: /* 5 */       MCD::OPC_CheckField, 2, 2, 0, 6, 0, // Skip to: 17
+// CHECK-NEXT: /* 11 */      MCD::OPC_TryDecode, {{[0-9]+}}, {{[0-9]+}}, 0, 0, 0, // Opcode: InstB, Skip to: 17
+// CHECK-NEXT: /* 17 */      MCD::OPC_Decode, {{[0-9]+}}, {{[0-9]+}}, 1, // Opcode: InstA
+// CHECK-NEXT: /* 21 */      MCD::OPC_Fail,
 
 // CHECK: if (!Check(S, DecodeInstB(MI, insn, Address, Decoder))) { DecodeComplete = false; return MCDisassembler::Fail; }
 
@@ -48,11 +48,11 @@ def InstB : TestInstruction {
 // CHECK-NEXT:  return NumToSkip;
 
 // CHECK-LARGE:      /* 0 */       MCD::OPC_ExtractField, 4, 4,  // Inst{7-4} ...
-// CHECK-LARGE-NEXT: /* 3 */       MCD::OPC_FilterValue, 0, 18, 0, 0, // Skip to: 26
-// CHECK-LARGE-NEXT: /* 8 */       MCD::OPC_CheckField, 2, 2, 0, 7, 0, 0, // Skip to: 22
-// CHECK-LARGE-NEXT: /* 15 */      MCD::OPC_TryDecode, {{[0-9]+}}, {{[0-9]+}}, 0, 0, 0, 0, // Opcode: InstB, skip to: 22
-// CHECK-LARGE-NEXT: /* 22 */      MCD::OPC_Decode, {{[0-9]+}}, {{[0-9]+}}, 1, // Opcode: InstA
-// CHECK-LARGE-NEXT: /* 26 */      MCD::OPC_Fail,
+// CHECK-LARGE-NEXT: /* 3 */       MCD::OPC_FilterValueOrFail, 0,
+// CHECK-LARGE-NEXT: /* 5 */       MCD::OPC_CheckField, 2, 2, 0, 7, 0, 0, // Skip to: 19
+// CHECK-LARGE-NEXT: /* 12 */      MCD::OPC_TryDecode, {{[0-9]+}}, {{[0-9]+}}, 0, 0, 0, 0, // Opcode: InstB, Skip to: 19
+// CHECK-LARGE-NEXT: /* 19 */      MCD::OPC_Decode, {{[0-9]+}}, {{[0-9]+}}, 1, // Opcode: InstA
+// CHECK-LARGE-NEXT: /* 23 */      MCD::OPC_Fail,
 
 // CHECK-LARGE: if (!Check(S, DecodeInstB(MI, insn, Address, Decoder))) { DecodeComplete = false; return MCDisassembler::Fail; }
 
diff --git a/llvm/test/TableGen/trydecode-emission2.td b/llvm/test/TableGen/trydecode-emission2.td
index 914e17c6f820c..593da63cd7616 100644
--- a/llvm/test/TableGen/trydecode-emission2.td
+++ b/llvm/test/TableGen/trydecode-emission2.td
@@ -32,27 +32,27 @@ def InstB : TestInstruction {
 }
 
 // CHECK:      /* 0 */       MCD::OPC_ExtractField, 2, 1,  // Inst{2} ...
-// CHECK-NEXT: /* 3 */       MCD::OPC_FilterValue, 0, 31, 0, // Skip to: 38
-// CHECK-NEXT: /* 7 */       MCD::OPC_ExtractField, 5, 3,  // Inst{7-5} ...
-// CHECK-NEXT: /* 10 */      MCD::OPC_FilterValue, 0, 24, 0, // Skip to: 38
-// CHECK-NEXT: /* 14 */      MCD::OPC_CheckField, 0, 2, 3, 6, 0, // Skip to: 26
-// CHECK-NEXT: /* 20 */      MCD::OPC_TryDecode, {{[0-9]+}}, {{[0-9]+}}, 0, 0, 0, // Opcode: InstB, skip to: 26
-// CHECK-NEXT: /* 26 */      MCD::OPC_CheckField, 3, 2, 0, 6, 0, // Skip to: 38
-// CHECK-NEXT: /* 32 */      MCD::OPC_TryDecode, {{[0-9]+}}, {{[0-9]+}}, 1, 0, 0, // Opcode: InstA, skip to: 38
-// CHECK-NEXT: /* 38 */      MCD::OPC_Fail,
+// CHECK-NEXT: /* 3 */       MCD::OPC_FilterValueOrFail, 0,
+// CHECK-NEXT: /* 5 */       MCD::OPC_ExtractField, 5, 3,  // Inst{7-5} ...
+// CHECK-NEXT: /* 8 */       MCD::OPC_FilterValueOrFail, 0
+// CHECK-NEXT: /* 10 */      MCD::OPC_CheckField, 0, 2, 3, 6, 0, // Skip to: 22
+// CHECK-NEXT: /* 16 */      MCD::OPC_TryDecode, {{[0-9]+}}, {{[0-9]+}}, 0, 0, 0, // Opcode: InstB, Skip to: 22
+// CHECK-NEXT: /* 22 */      MCD::OPC_CheckFieldOrFail, 3, 2, 0,
+// CHECK-NEXT: /* 26 */      MCD::OPC_TryDecodeOrFail, {{[0-9]+}}, {{[0-9]+}}, 1,
+// CHECK-NEXT: /* 30 */      MCD::OPC_Fail,
 
 // CHECK: if (!Check(S, DecodeInstB(MI, insn, Address, Decoder))) { DecodeComplete = false; return MCDisassembler::Fail; }
 // CHECK: if (!Check(S, DecodeInstA(MI, insn, Address, Decoder))) { DecodeComplete = false; return MCDisassembler::Fail; }
 
 // CHECK-LARGE:      /* 0 */       MCD::OPC_ExtractField, 2, 1,  // Inst{2} ...
-// CHECK-LARGE-NEXT: /* 3 */       MCD::OPC_FilterValue, 0, 36, 0, 0, // Skip to: 44
-// CHECK-LARGE-NEXT: /* 8 */       MCD::OPC_ExtractField, 5, 3,  // Inst{7-5} ...
-// CHECK-LARGE-NEXT: /* 11 */      MCD::OPC_FilterValue, 0, 28, 0, 0, // Skip to: 44
-// CHECK-LARGE-NEXT: /* 16 */      MCD::OPC_CheckField, 0, 2, 3, 7, 0, 0, // Skip to: 30
-// CHECK-LARGE-NEXT: /* 23 */      MCD::OPC_TryDecode, {{[0-9]+}}, {{[0-9]+}}, 0, 0, 0, 0, // Opcode: InstB, skip to: 30
-// CHECK-LARGE-NEXT: /* 30 */      MCD::OPC_CheckField, 3, 2, 0, 7, 0, 0, // Skip to: 44
-// CHECK-LARGE-NEXT: /* 37 */      MCD::OPC_TryDecode, {{[0-9]+}}, {{[0-9]+}}, 1, 0, 0, 0, // Opcode: InstA, skip to: 44
-// CHECK-LARGE-NEXT: /* 44 */      MCD::OPC_Fail,
+// CHECK-LARGE-NEXT: /* 3 */       MCD::OPC_FilterValueOrFail, 0,
+// CHECK-LARGE-NEXT: /* 5 */       MCD::OPC_ExtractField, 5, 3,  // Inst{7-5} ...
+// CHECK-LARGE-NEXT: /* 8 */       MCD::OPC_FilterValueOrFail, 0,
+// CHECK-LARGE-NEXT: /* 10 */      MCD::OPC_CheckField, 0, 2, 3, 7, 0, 0, // Skip to: 24
+// CHECK-LARGE-NEXT: /* 17 */      MCD::OPC_TryDecode, {{[0-9]+}}, {{[0-9]+}}, 0, 0, 0, 0, // Opcode: InstB, Skip to: 24
+// CHECK-LARGE-NEXT: /* 24 */      MCD::OPC_CheckFieldOrFail, 3, 2, 0,
+// CHECK-LARGE-NEXT: /* 28 */      MCD::OPC_TryDecodeOrFail, {{[0-9]+}}, {{[0-9]+}}, 1,
+// CHECK-LARGE-NEXT: /* 32 */      MCD::OPC_Fail,
 
 // CHECK-LARGE: if (!Check(S, DecodeInstB(MI, insn, Address, Decoder))) { DecodeComplete = false; return MCDisassembler::Fail; }
 // CHECK-LARGE: if (!Check(S, DecodeInstA(MI, insn, Address, Decoder))) { DecodeComplete = false; return MCDisassembler::Fail; }
diff --git a/llvm/test/TableGen/trydecode-emission3.td b/llvm/test/TableGen/trydecode-emission3.td
index 141dc5439ca13..e2b739d8338de 100644
--- a/llvm/test/TableGen/trydecode-emission3.td
+++ b/llvm/test/TableGen/trydecode-emission3.td
@@ -36,19 +36,19 @@ def InstB : TestInstruction {
 }
 
 // CHECK:      /* 0 */       MCD::OPC_ExtractField, 4, 4,  // Inst{7-4} ...
-// CHECK-NEXT: /* 3 */       MCD::OPC_FilterValue, 0, 16, 0, // Skip to: 23
-// CHECK-NEXT: /* 7 */       MCD::OPC_CheckField, 2, 2, 0, 6, 0, // Skip to: 19
-// CHECK-NEXT: /* 13 */      MCD::OPC_TryDecode, {{[0-9]+}}, {{[0-9]+}}, 0, 0, 0, // Opcode: InstB, skip to: 19
-// CHECK-NEXT: /* 19 */      MCD::OPC_Decode, {{[0-9]+}}, {{[0-9]+}}, 1, // Opcode: InstA
-// CHECK-NEXT: /* 23 */      MCD::OPC_Fail,
+// CHECK-NEXT: /* 3 */       MCD::OPC_FilterValueOrFail, 0,
+// CHECK-NEXT: /* 5 */       MCD::OPC_CheckField, 2, 2, 0, 6, 0, // Skip to: 17
+// CHECK-NEXT: /* 11 */      MCD::OPC_TryDecode, {{[0-9]+}}, {{[0-9]+}}, 0, 0, 0, // Opcode: InstB, Skip to: 17
+// CHECK-NEXT: /* 17 */      MCD::OPC_Decode, {{[0-9]+}}, {{[0-9]+}}, 1, // Opcode: InstA
+// CHECK-NEXT: /* 21 */      MCD::OPC_Fail,
 
 // CHECK: if (!Check(S, DecodeInstBOp(MI, tmp, Address, Decoder))) { DecodeComplete = false; return MCDisassembler::Fail; }
 
 // CHECK-LARGE:      /* 0 */       MCD::OPC_ExtractField, 4, 4,  // Inst{7-4} ...
-// CHECK-LARGE-NEXT: /* 3 */       MCD::OPC_FilterValue, 0, 18, 0, 0, // Skip to: 26
-// CHECK-LARGE-NEXT: /* 8 */       MCD::OPC_CheckField, 2, 2, 0, 7, 0, 0, // Skip to: 22
-// CHECK-LARGE-NEXT: /* 15 */      MCD::OPC_TryDecode, {{[0-9]+}}, {{[0-9]+}}, 0, 0, 0, 0, // Opcode: InstB, skip to: 22
-// CHECK-LARGE-NEXT: /* 22 */      MCD::OPC_Decode, {{[0-9]+}}, {{[0-9]+}}, 1, // Opcode: InstA
-// CHECK-LARGE-NEXT: /* 26 */      MCD::OPC_Fail,
+// CHECK-LARGE-NEXT: /* 3 */       MCD::OPC_FilterValueOrFail, 0,
+// CHECK-LARGE-NEXT: /* 5 */       MCD::OPC_CheckField, 2, 2, 0, 7, 0, 0, // Skip to: 19
+// CHECK-LARGE-NEXT: /* 12 */      MCD::OPC_TryDecode, {{[0-9]+}}, {{[0-9]+}}, 0, 0, 0, 0, // Opcode: InstB, Skip to: 19
+// CHECK-LARGE-NEXT: /* 19 */      MCD::OPC_Decode, {{[0-9]+}}, {{[0-9]+}}, 1, // Opcode: InstA
+// CHECK-LARGE-NEXT: /* 23 */      MCD::OPC_Fail,
 
 // CHECK-LARGE: if (!Check(S, DecodeInstBOp(MI, tmp, Address, Decoder))) { DecodeComplete = false; return MCDisassembler::Fail; }
diff --git a/llvm/test/TableGen/trydecode-emission4.td b/llvm/test/TableGen/trydecode-emission4.td
index bb44876e77f02..39a3187c38bda 100644
--- a/llvm/test/TableGen/trydecode-emission4.td
+++ b/llvm/test/TableGen/trydecode-emission4.td
@@ -34,21 +34,21 @@ def InstB : TestInstruction {
 }
 
 // CHECK:      /* 0 */       MCD::OPC_ExtractField, 250, 3, 4,  // Inst{509-506} ...
-// CHECK-NEXT: /* 4 */       MCD::OPC_FilterValue, 0, 17, 0, // Skip to: 25
-// CHECK-NEXT: /* 8 */       MCD::OPC_CheckField, 248, 3, 2, 0, 6, 0, // Skip to: 21
-// CHECK-NEXT: /* 15 */      MCD::OPC_TryDecode, {{[0-9]+}}, {{[0-9]+}}, 0, 0, 0, // Opcode: InstB, skip to: 21
-// CHECK-NEXT: /* 21 */      MCD::OPC_Decode, {{[0-9]+}}, {{[0-9]+}}, 1, // Opcode: InstA
-// CHECK-NEXT: /* 25 */      MCD::OPC_Fail,
+// CHECK-NEXT: /* 4 */       MCD::OPC_FilterValueOrFail, 0,
+// CHECK-NEXT: /* 6 */       MCD::OPC_CheckField, 248, 3, 2, 0, 6, 0, // Skip to: 19
+// CHECK-NEXT: /* 13 */      MCD::OPC_TryDecode, {{[0-9]+}}, {{[0-9]+}}, 0, 0, 0, // Opcode: InstB, Skip to: 19
+// CHECK-NEXT: /* 19 */      MCD::OPC_Decode, {{[0-9]+}}, {{[0-9]+}}, 1, // Opcode: InstA
+// CHECK-NEXT: /* 23 */      MCD::OPC_Fail,
 
 // CHECK: if (!Check(S, DecodeInstB(MI, insn, Address, Decoder))) { DecodeComplete = false; return MCDisassembler::Fail; }
 
 
 // CHECK-LARGE:      /* 0 */       MCD::OPC_ExtractField, 250, 3, 4,  // Inst{509-506} ...
-// CHECK-LARGE-NEXT: /* 4 */       MCD::OPC_FilterValue, 0, 19, 0, 0, // Skip to: 28
-// CHECK-LARGE-NEXT: /* 9 */       MCD::OPC_CheckField, 248, 3, 2, 0, 7, 0, 0, // Skip to: 24
-// CHECK-LARGE-NEXT: /* 17 */      MCD::OPC_TryDecode, {{[0-9]+}}, {{[0-9]+}}, 0, 0, 0, 0, // Opcode: InstB, skip to: 24
-// CHECK-LARGE-NEXT: /* 24 */      MCD::OPC_Decode, {{[0-9]+}}, {{[0-9]+}}, 1, // Opcode: InstA
-// CHECK-LARGE-NEXT: /* 28 */      MCD::OPC_Fail,
+// CHECK-LARGE-NEXT: /* 4 */       MCD::OPC_FilterValueOrFail, 0,
+// CHECK-LARGE-NEXT: /* 6 */       MCD::OPC_CheckField, 248, 3, 2, 0, 7, 0, 0, // Skip to: 21
+// CHECK-LARGE-NEXT: /* 14 */      MCD::OPC_TryDecode, {{[0-9]+}}, {{[0-9]+}}, 0, 0, 0, 0, // Opcode: InstB, Skip to: 21
+// CHECK-LARGE-NEXT: /* 21 */      MCD::OPC_Decode, {{[0-9]+}}, {{[0-9]+}}, 1, // Opcode: InstA
+// CHECK-LARGE-NEXT: /* 25 */      MCD::OPC_Fail,
 
 // CHECK-LARGE: if (!Check(S, DecodeInstB(MI, insn, Address, Decoder))) { DecodeComplete = false; return MCDisassembler::Fail; }
 
diff --git a/llvm/utils/TableGen/DecoderEmitter.cpp b/llvm/utils/TableGen/DecoderEmitter.cpp
index 82ba93534cbda..3990836e9077f 100644
--- a/llvm/utils/TableGen/DecoderEmitter.cpp
+++ b/llvm/utils/TableGen/DecoderEmitter.cpp
@@ -90,9 +90,9 @@ STATISTIC(NumInstructions, "Number of instructions considered");
 STATISTIC(NumEncodingsSupported, "Number of encodings supported");
 STATISTIC(NumEncodingsOmitted, "Number of encodings omitted");
 
-namespace {
+static unsigned getNumToSkipInBytes() { return LargeTable ? 3 : 2; }
 
-unsigned getNumToSkipInBytes() { return LargeTable ? 3 : 2; }
+namespace {
 
 struct EncodingField {
   unsigned Base, Width, Offset;
@@ -182,6 +182,8 @@ struct DecoderTableInfo {
   FixupScopeList FixupStack;
   PredicateSet Predicates;
   DecoderSet Decoders;
+
+  bool isOutermostScope() const { return FixupStack.size() == 1; }
 };
 
 struct EncodingAndInst {
@@ -777,11 +779,21 @@ void Filter::emitTableEntry(DecoderTableInfo &TableInfo) const {
 
       PrevFilter = 0; // Don't re-process the filter's fallthrough.
     } else {
-      Table.push_back(MCD::OPC_FilterValue);
+      // The last filtervalue emitted can be OPC_FilterValue if we are at
+      // outermost scope.
+      const uint8_t DecoderOp =
+          FilterVal == LastFilter && TableInfo.isOutermostScope()
+              ? MCD::OPC_FilterValueOrFail
+              : MCD::OPC_FilterValue;
+      Table.push_back(DecoderOp);
       Table.insertULEB128(FilterVal);
-      // Reserve space for the NumToSkip entry. We'll backpatch the value
-      // later.
-      PrevFilter = Table.insertNumToSkip();
+      if (DecoderOp == MCD::OPC_FilterValue) {
+        // Reserve space for the NumToSkip entry. We'll backpatch the value
+        // later.
+        PrevFilter = Table.insertNumToSkip();
+      } else {
+        PrevFilter = 0;
+      }
     }
 
     // We arrive at a category of instructions with the same segment value.
@@ -796,9 +808,10 @@ void Filter::emitTableEntry(DecoderTableInfo &TableInfo) const {
       Table.patchNumToSkip(PrevFilter, Table.size());
   }
 
-  // If there is no fallthrough, then the final filter should get fixed
-  // up according to the enclosing scope rather than the current position.
-  if (!HasFallthrough)
+  // If there is no fallthrough and the final filter was not in the outermost
+  // scope, then it must be fixed up according to the enclosing scope rather
+  // than the current position.
+  if (PrevFilter)
     TableInfo.FixupStack.back().push_back(PrevFilter);
 }
 
@@ -863,6 +876,15 @@ void DecoderEmitter::emitTable(formatted_raw_ostream &OS, DecoderTable &Table,
   DecoderTable::const_iterator I = Table.begin();
   DecoderTable::const_iterator E = Table.end();
   const uint8_t *const EndPtr = Table.data() + Table.size();
+
+  auto emitNumToSkipComment = [&](uint32_t NumToSkip, bool InComment = false) {
+    uint32_t Index = ((I - Table.begin()) + NumToSkip);
+    OS << (InComment ? ", " : "// ");
+    OS << "Skip to: " << Index;
+    if (*(I + NumToSkip) == MCD::OPC_Fail)
+      OS << " (Fail)";
+  };
+
   while (I != E) {
     assert(I < E && "incomplete decode table entry!");
 
@@ -873,7 +895,8 @@ void DecoderEmitter::emitTable(formatted_raw_ostream &OS, DecoderTable &Table,
     const uint8_t DecoderOp = *I++;
     switch (DecoderOp) {
     default:
-      PrintFatalError("Invalid decode table opcode: " + Twine(DecoderOp));
+      PrintFatalError("Invalid decode table opcode: " + Twine((int)DecoderOp) +
+                      " at index " + Twine(Pos));
     case MCD::OPC_ExtractField: {
       OS << Indent << "MCD::OPC_ExtractField, ";
 
@@ -890,17 +913,24 @@ void DecoderEmitter::emitTable(formatted_raw_ostream &OS, DecoderTable &Table,
       OS << Start << "} ...\n";
       break;
     }
-    case MCD::OPC_FilterValue: {
-      OS << Indent << "MCD::OPC_FilterValue, ";
+    case MCD::OPC_FilterValue:
+    case MCD::OPC_FilterValueOrFail: {
+      bool IsFail = DecoderOp == MCD::OPC_FilterValueOrFail;
+      OS << Indent << "MCD::OPC_FilterValue" << (IsFail ? "OrFail, " : ", ");
       // The filter value is ULEB128 encoded.
       emi...
[truncated]

@jurahul jurahul requested a review from topperc May 28, 2025 14:31
@jurahul jurahul requested a review from s-barannikov May 31, 2025 13:23
@jurahul
Copy link
Contributor Author

jurahul commented May 31, 2025

I also found another minor improvement here: Most targets don't generate TryDecode (only AArch64 seems to be generating it), so we could not emit the TryDecode cases for other targets (by tracking whether any TryDecode ops are generated) and eliminate some dead code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend:AArch64 bazel "Peripheral" support tier build system: utils/bazel tablegen
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants