[llvm] [TableGen][DecoderEmitter] Avoid using a sentinel value (PR #153986)

Sergei Barannikov via llvm-commits llvm-commits at lists.llvm.org
Sat Aug 16 17:29:29 PDT 2025


https://github.com/s-barannikov created https://github.com/llvm/llvm-project/pull/153986

`NO_FIXED_SEGMENTS_SENTINEL` has a value that is actually a valid field encoding and so it cannot be used as a sentinel.
Replace the sentinel with a new member variable, `VariableFC`, that contains the value previously stored in `FilterChooserMap` with `NO_FIXED_SEGMENTS_SENTINEL` key.

>From 3ea4400ca4fa38fdeae810d0265206eb6cdd93a0 Mon Sep 17 00:00:00 2001
From: Sergei Barannikov <barannikov88 at gmail.com>
Date: Sun, 17 Aug 2025 03:29:00 +0300
Subject: [PATCH] [TableGen][DecoderEmitter] Avoid using a sentinel value

`NO_FIXED_SEGMENTS_SENTINEL` has a value that is actually a valid field
encoding and so it cannot be used as a sentinel.
Replace the sentinel with a new member variable, `VariableFC`, that
contains the value previously stored in `FilterChooserMap` with
`NO_FIXED_SEGMENTS_SENTINEL` key.
---
 llvm/utils/TableGen/DecoderEmitter.cpp | 82 ++++++++++++--------------
 1 file changed, 39 insertions(+), 43 deletions(-)

diff --git a/llvm/utils/TableGen/DecoderEmitter.cpp b/llvm/utils/TableGen/DecoderEmitter.cpp
index b22c60a00081d..ca0145d37c080 100644
--- a/llvm/utils/TableGen/DecoderEmitter.cpp
+++ b/llvm/utils/TableGen/DecoderEmitter.cpp
@@ -339,9 +339,6 @@ typedef std::vector<BitValue> insn_t;
 
 namespace {
 
-static constexpr uint64_t NO_FIXED_SEGMENTS_SENTINEL =
-    std::numeric_limits<uint64_t>::max();
-
 class FilterChooser;
 
 /// Filter - Filter works with FilterChooser to produce the decoding tree for
@@ -395,6 +392,9 @@ class Filter {
   // Map of well-known segment value to its delegate.
   std::map<uint64_t, std::unique_ptr<const FilterChooser>> FilterChooserMap;
 
+  // A filter chooser for encodings that contain some '?' in the filtered range.
+  std::unique_ptr<const FilterChooser> VariableFC;
+
   // Number of instructions which fall under FilteredInstructions category.
   unsigned NumFiltered;
 
@@ -417,8 +417,8 @@ class Filter {
   // Return the filter chooser for the group of instructions without constant
   // segment values.
   const FilterChooser &getVariableFC() const {
-    assert(NumFiltered == 1 && FilterChooserMap.size() == 1);
-    return *(FilterChooserMap.find(NO_FIXED_SEGMENTS_SENTINEL)->second);
+    assert(NumFiltered == 1 && FilterChooserMap.empty());
+    return *VariableFC;
   }
 
   // Divides the decoding task into sub tasks and delegates them to the
@@ -650,7 +650,8 @@ Filter::Filter(Filter &&f)
       FilteredInstructions(std::move(f.FilteredInstructions)),
       VariableInstructions(std::move(f.VariableInstructions)),
       FilterChooserMap(std::move(f.FilterChooserMap)),
-      NumFiltered(f.NumFiltered), LastOpcFiltered(f.LastOpcFiltered) {}
+      VariableFC(std::move(f.VariableFC)), NumFiltered(f.NumFiltered),
+      LastOpcFiltered(f.LastOpcFiltered) {}
 
 Filter::Filter(const FilterChooser &owner, unsigned startBit, unsigned numBits)
     : Owner(owner), StartBit(startBit), NumBits(numBits) {
@@ -700,17 +701,15 @@ void Filter::recurse() {
 
     // Delegates to an inferior filter chooser for further processing on this
     // group of instructions whose segment values are variable.
-    FilterChooserMap.try_emplace(
-        NO_FIXED_SEGMENTS_SENTINEL,
-        std::make_unique<FilterChooser>(Owner.AllInstructions,
-                                        VariableInstructions, Owner.Operands,
-                                        BitValueArray, Owner));
+    VariableFC = std::make_unique<FilterChooser>(
+        Owner.AllInstructions, VariableInstructions, Owner.Operands,
+        BitValueArray, Owner);
   }
 
   // No need to recurse for a singleton filtered instruction.
   // See also Filter::emit*().
   if (getNumFiltered() == 1) {
-    assert(FilterChooserMap.size() == 1);
+    assert(VariableFC && "Shouldn't have created Filter for one encoding");
     return;
   }
 
@@ -756,44 +755,26 @@ void Filter::emitTableEntry(DecoderTableInfo &TableInfo) const {
   // FilterChooserMap.
 
   const uint64_t LastFilter = FilterChooserMap.rbegin()->first;
-  bool HasFallthrough = LastFilter == NO_FIXED_SEGMENTS_SENTINEL;
-  if (HasFallthrough)
+  if (VariableFC)
     TableInfo.FixupStack.emplace_back();
 
   DecoderTable &Table = TableInfo.Table;
 
   size_t PrevFilter = 0;
   for (const auto &[FilterVal, Delegate] : FilterChooserMap) {
-    // Field value NO_FIXED_SEGMENTS_SENTINEL implies a non-empty set of
-    // variable instructions. See also recurse().
-    if (FilterVal == NO_FIXED_SEGMENTS_SENTINEL) {
-      // Each scope should always have at least one filter value to check
-      // for.
-      assert(PrevFilter != 0 && "empty filter set!");
-      FixupList &CurScope = TableInfo.FixupStack.back();
-      // Resolve any NumToSkip fixups in the current scope.
-      resolveTableFixups(Table, CurScope, Table.size());
-
-      // Delete the scope we have added here.
-      TableInfo.FixupStack.pop_back();
-
-      PrevFilter = 0; // Don't re-process the filter's fallthrough.
+    // 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);
+    if (DecoderOp == MCD::OPC_FilterValue) {
+      // Reserve space for the NumToSkip entry. We'll backpatch the value later.
+      PrevFilter = Table.insertNumToSkip();
     } else {
-      // 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);
-      if (DecoderOp == MCD::OPC_FilterValue) {
-        // Reserve space for the NumToSkip entry. We'll backpatch the value
-        // later.
-        PrevFilter = Table.insertNumToSkip();
-      } else {
-        PrevFilter = 0;
-      }
+      PrevFilter = 0;
     }
 
     // We arrive at a category of instructions with the same segment value.
@@ -808,6 +789,21 @@ void Filter::emitTableEntry(DecoderTableInfo &TableInfo) const {
       Table.patchNumToSkip(PrevFilter, Table.size());
   }
 
+  if (VariableFC) {
+    // Each scope should always have at least one filter value to check for.
+    assert(PrevFilter != 0 && "empty filter set!");
+    // Resolve any NumToSkip fixups in the current scope.
+    resolveTableFixups(Table, TableInfo.FixupStack.back(), Table.size());
+
+    // Delete the scope we have added here.
+    TableInfo.FixupStack.pop_back();
+
+    PrevFilter = 0; // Don't re-process the filter's fallthrough.
+
+    // Delegate to the sub filter chooser for further decoding.
+    VariableFC->emitTableEntries(TableInfo);
+  }
+
   // 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.



More information about the llvm-commits mailing list