[llvm] [TableGen][DecoderEmitter] Compute bit attribute once (NFC) (PR #153530)

Sergei Barannikov via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 13 20:32:45 PDT 2025


https://github.com/s-barannikov updated https://github.com/llvm/llvm-project/pull/153530

>From 0e0ae58cab2ff69a9f6d90da42be5191ef94a03b Mon Sep 17 00:00:00 2001
From: Sergei Barannikov <barannikov88 at gmail.com>
Date: Thu, 14 Aug 2025 06:18:02 +0300
Subject: [PATCH] [TableGen][DecoderEmitter] Compute bit attribute once (NFC)

Pull the logic to compute bit attributes from `filterProcessor()`
to its caller to avoid recomputing them on the second call.
---
 llvm/utils/TableGen/DecoderEmitter.cpp | 130 +++++++++++++------------
 1 file changed, 66 insertions(+), 64 deletions(-)

diff --git a/llvm/utils/TableGen/DecoderEmitter.cpp b/llvm/utils/TableGen/DecoderEmitter.cpp
index 997f9a585d3ad..59ad70d1a7002 100644
--- a/llvm/utils/TableGen/DecoderEmitter.cpp
+++ b/llvm/utils/TableGen/DecoderEmitter.cpp
@@ -623,7 +623,8 @@ class FilterChooser {
   // FilterProcessor scans the well-known encoding bits of the instructions and
   // builds up a list of candidate filters.  It chooses the best filter and
   // recursively descends down the decoding tree.
-  bool filterProcessor(bool AllowMixed, bool Greedy = true);
+  bool filterProcessor(ArrayRef<bitAttr_t> BitAttrs, bool AllowMixed,
+                       bool Greedy = true);
 
   // Decides on the best configuration of filter(s) to use in order to decode
   // the instructions.  A conflict of instructions may occur, in which case we
@@ -1550,21 +1551,17 @@ void FilterChooser::reportRegion(bitAttr_t RA, unsigned StartBit,
 // FilterProcessor scans the well-known encoding bits of the instructions and
 // builds up a list of candidate filters.  It chooses the best filter and
 // recursively descends down the decoding tree.
-bool FilterChooser::filterProcessor(bool AllowMixed, bool Greedy) {
+bool FilterChooser::filterProcessor(ArrayRef<bitAttr_t> BitAttrs,
+                                    bool AllowMixed, bool Greedy) {
   Filters.clear();
   BestIndex = -1;
-  unsigned numInstructions = Opcodes.size();
 
-  assert(numInstructions && "Filter created with no instructions");
-
-  // No further filtering is necessary.
-  if (numInstructions == 1)
-    return true;
+  assert(Opcodes.size() >= 2 && "Nothing to filter");
 
   // Heuristics.  See also doFilter()'s "Heuristics" comment when num of
   // instructions is 3.
   if (AllowMixed && !Greedy) {
-    assert(numInstructions == 3);
+    assert(Opcodes.size() == 3);
 
     for (const auto &Opcode : Opcodes) {
       insn_t Insn = insnWithID(Opcode.EncodingID);
@@ -1579,57 +1576,6 @@ bool FilterChooser::filterProcessor(bool AllowMixed, bool Greedy) {
     }
   }
 
-  // We maintain BIT_WIDTH copies of the bitAttrs automaton.
-  // The automaton consumes the corresponding bit from each
-  // instruction.
-  //
-  //   Input symbols: 0, 1, and _ (unset).
-  //   States:        NONE, FILTERED, ALL_SET, ALL_UNSET, and MIXED.
-  //   Initial state: NONE.
-  //
-  // (NONE) ------- [01] -> (ALL_SET)
-  // (NONE) ------- _ ----> (ALL_UNSET)
-  // (ALL_SET) ---- [01] -> (ALL_SET)
-  // (ALL_SET) ---- _ ----> (MIXED)
-  // (ALL_UNSET) -- [01] -> (MIXED)
-  // (ALL_UNSET) -- _ ----> (ALL_UNSET)
-  // (MIXED) ------ . ----> (MIXED)
-  // (FILTERED)---- . ----> (FILTERED)
-
-  std::vector<bitAttr_t> bitAttrs(BitWidth, ATTR_NONE);
-
-  // FILTERED bit positions provide no entropy and are not worthy of pursuing.
-  // Filter::recurse() set either BIT_TRUE or BIT_FALSE for each position.
-  for (unsigned BitIndex = 0; BitIndex < BitWidth; ++BitIndex)
-    if (FilterBitValues[BitIndex].isSet())
-      bitAttrs[BitIndex] = ATTR_FILTERED;
-
-  for (const auto &OpcPair : Opcodes) {
-    insn_t insn = insnWithID(OpcPair.EncodingID);
-
-    for (unsigned BitIndex = 0; BitIndex < BitWidth; ++BitIndex) {
-      switch (bitAttrs[BitIndex]) {
-      case ATTR_NONE:
-        if (insn[BitIndex] == BitValue::BIT_UNSET)
-          bitAttrs[BitIndex] = ATTR_ALL_UNSET;
-        else
-          bitAttrs[BitIndex] = ATTR_ALL_SET;
-        break;
-      case ATTR_ALL_SET:
-        if (insn[BitIndex] == BitValue::BIT_UNSET)
-          bitAttrs[BitIndex] = ATTR_MIXED;
-        break;
-      case ATTR_ALL_UNSET:
-        if (insn[BitIndex] != BitValue::BIT_UNSET)
-          bitAttrs[BitIndex] = ATTR_MIXED;
-        break;
-      case ATTR_MIXED:
-      case ATTR_FILTERED:
-        break;
-      }
-    }
-  }
-
   // The regionAttr automaton consumes the bitAttrs automatons' state,
   // lowest-to-highest.
   //
@@ -1654,7 +1600,7 @@ bool FilterChooser::filterProcessor(bool AllowMixed, bool Greedy) {
   unsigned StartBit = 0;
 
   for (unsigned BitIndex = 0; BitIndex < BitWidth; ++BitIndex) {
-    bitAttr_t bitAttr = bitAttrs[BitIndex];
+    bitAttr_t bitAttr = BitAttrs[BitIndex];
 
     assert(bitAttr != ATTR_NONE && "Bit without attributes");
 
@@ -1774,19 +1720,75 @@ void FilterChooser::doFilter() {
   unsigned Num = Opcodes.size();
   assert(Num && "FilterChooser created with no instructions");
 
+  // No filter needed.
+  if (Opcodes.size() < 2)
+    return;
+
+  // We maintain BIT_WIDTH copies of the bitAttrs automaton.
+  // The automaton consumes the corresponding bit from each
+  // instruction.
+  //
+  //   Input symbols: 0, 1, _ (unset), and . (any of the above).
+  //   States:        NONE, FILTERED, ALL_SET, ALL_UNSET, and MIXED.
+  //   Initial state: NONE.
+  //
+  // (NONE) ------- [01] -> (ALL_SET)
+  // (NONE) ------- _ ----> (ALL_UNSET)
+  // (ALL_SET) ---- [01] -> (ALL_SET)
+  // (ALL_SET) ---- _ ----> (MIXED)
+  // (ALL_UNSET) -- [01] -> (MIXED)
+  // (ALL_UNSET) -- _ ----> (ALL_UNSET)
+  // (MIXED) ------ . ----> (MIXED)
+  // (FILTERED)---- . ----> (FILTERED)
+
+  SmallVector<bitAttr_t, 128> BitAttrs(BitWidth, ATTR_NONE);
+
+  // FILTERED bit positions provide no entropy and are not worthy of pursuing.
+  // Filter::recurse() set either BIT_TRUE or BIT_FALSE for each position.
+  for (unsigned BitIndex = 0; BitIndex < BitWidth; ++BitIndex)
+    if (FilterBitValues[BitIndex].isSet())
+      BitAttrs[BitIndex] = ATTR_FILTERED;
+
+  for (const EncodingIDAndOpcode &OpcPair : Opcodes) {
+    insn_t EncodingBits = insnWithID(OpcPair.EncodingID);
+
+    for (unsigned BitIndex = 0; BitIndex < BitWidth; ++BitIndex) {
+      switch (BitAttrs[BitIndex]) {
+      case ATTR_NONE:
+        if (EncodingBits[BitIndex] == BitValue::BIT_UNSET)
+          BitAttrs[BitIndex] = ATTR_ALL_UNSET;
+        else
+          BitAttrs[BitIndex] = ATTR_ALL_SET;
+        break;
+      case ATTR_ALL_SET:
+        if (EncodingBits[BitIndex] == BitValue::BIT_UNSET)
+          BitAttrs[BitIndex] = ATTR_MIXED;
+        break;
+      case ATTR_ALL_UNSET:
+        if (EncodingBits[BitIndex] != BitValue::BIT_UNSET)
+          BitAttrs[BitIndex] = ATTR_MIXED;
+        break;
+      case ATTR_MIXED:
+      case ATTR_FILTERED:
+        break;
+      }
+    }
+  }
+
   // Try regions of consecutive known bit values first.
-  if (filterProcessor(false))
+  if (filterProcessor(BitAttrs, /*AllowMixed=*/false))
     return;
 
   // Then regions of mixed bits (both known and unitialized bit values allowed).
-  if (filterProcessor(true))
+  if (filterProcessor(BitAttrs, /*AllowMixed=*/true))
     return;
 
   // Heuristics to cope with conflict set {t2CMPrs, t2SUBSrr, t2SUBSrs} where
   // no single instruction for the maximum ATTR_MIXED region Inst{14-4} has a
   // well-known encoding pattern.  In such case, we backtrack and scan for the
   // the very first consecutive ATTR_ALL_SET region and assign a filter to it.
-  if (Num == 3 && filterProcessor(true, false))
+  if (Num == 3 &&
+      filterProcessor(BitAttrs, /*AllowMixed=*/true, /*Greedy=*/false))
     return;
 
   // If we come to here, the instruction decoding has failed.



More information about the llvm-commits mailing list