[llvm] 483d534 - [TargetParser][NFC] Make FeatureBitset iterable (#206394)

via llvm-commits llvm-commits at lists.llvm.org
Tue Jun 30 18:56:30 PDT 2026


Author: Mark Zhuang
Date: 2026-07-01T09:56:25+08:00
New Revision: 483d53409dd5b1540c1b0644b31c392e4a1b0406

URL: https://github.com/llvm/llvm-project/commit/483d53409dd5b1540c1b0644b31c392e4a1b0406
DIFF: https://github.com/llvm/llvm-project/commit/483d53409dd5b1540c1b0644b31c392e4a1b0406.diff

LOG: [TargetParser][NFC] Make FeatureBitset iterable (#206394)

FeatureBitset had no way to iterate its bits, so callers scanned all
MAX_SUBTARGET_FEATURES positions by hand.
This adds begin()/end() that yield the index of each set bit, skipping
unset bits with countr_zero.
Callers can now write `for (unsigned Feature: Features)`. 

Assisted-by: claude-opus

Added: 
    

Modified: 
    llvm/include/llvm/TargetParser/SubtargetFeature.h
    llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
    llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
    llvm/lib/Target/CSKY/AsmParser/CSKYAsmParser.cpp
    llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp
    llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
    llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp
    llvm/unittests/TargetParser/TargetParserTest.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/TargetParser/SubtargetFeature.h b/llvm/include/llvm/TargetParser/SubtargetFeature.h
index a48b18745352a..3c136b27374dd 100644
--- a/llvm/include/llvm/TargetParser/SubtargetFeature.h
+++ b/llvm/include/llvm/TargetParser/SubtargetFeature.h
@@ -20,6 +20,7 @@
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/iterator.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/MathExtras.h"
 #include <array>
@@ -84,6 +85,45 @@ class FeatureBitset {
 
   constexpr size_t size() const { return MAX_SUBTARGET_FEATURES; }
 
+  /// Index of the first set bit at or after Begin, or size() if none.
+  unsigned find_first_from(unsigned Begin) const {
+    for (unsigned Word = Begin / 64; Word < Bits.size(); ++Word) {
+      uint64_t Masked = Bits[Word] & maskTrailingZeros<uint64_t>(Begin % 64);
+      if (Masked)
+        return Word * 64 + llvm::countr_zero(Masked);
+      Begin = (Word + 1) * 64;
+    }
+    return size();
+  }
+
+  /// Yields the index of each set bit, skipping unset bits via countr_zero.
+  class const_iterator
+      : public iterator_facade_base<const_iterator, std::forward_iterator_tag,
+                                    const unsigned, std::ptr
diff _t,
+                                    const unsigned *, unsigned> {
+    const FeatureBitset *Parent = nullptr;
+    unsigned Index = 0;
+
+  public:
+    const_iterator() = default;
+    const_iterator(const FeatureBitset &Parent, unsigned Index)
+        : Parent(&Parent), Index(Index) {}
+
+    unsigned operator*() const { return Index; }
+    const_iterator &operator++() {
+      Index = Parent->find_first_from(Index + 1);
+      return *this;
+    }
+    bool operator==(const const_iterator &RHS) const {
+      return Index == RHS.Index;
+    }
+  };
+
+  const_iterator begin() const {
+    return const_iterator(*this, find_first_from(0));
+  }
+  const_iterator end() const { return const_iterator(*this, size()); }
+
   bool any() const {
     return llvm::any_of(Bits, [](uint64_t I) { return I != 0; });
   }

diff  --git a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
index b3fda2fe849fa..6e6c0050cce71 100644
--- a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
+++ b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
@@ -6998,11 +6998,9 @@ bool AArch64AsmParser::matchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
     // Special case the error message for the very common case where only
     // a single subtarget feature is missing (neon, e.g.).
     std::string Msg = "instruction requires:";
-    for (unsigned i = 0, e = MissingFeatures.size(); i != e; ++i) {
-      if (MissingFeatures[i]) {
-        Msg += " ";
-        Msg += getSubtargetFeatureName(i);
-      }
+    for (unsigned Feature : MissingFeatures) {
+      Msg += " ";
+      Msg += getSubtargetFeatureName(Feature);
     }
     return Error(IDLoc, Msg);
   }

diff  --git a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
index bd90afd9e77d0..9973f73c5cb71 100644
--- a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
+++ b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
@@ -12857,9 +12857,8 @@ ARMAsmParser::FilterNearMisses(SmallVectorImpl<NearMissInfo> &NearMissesIn,
       raw_svector_ostream OS(Message.Message);
 
       OS << "instruction requires:";
-      for (unsigned i = 0, e = MissingFeatures.size(); i != e; ++i)
-        if (MissingFeatures.test(i))
-          OS << ' ' << getSubtargetFeatureName(i);
+      for (unsigned Feature : MissingFeatures)
+        OS << ' ' << getSubtargetFeatureName(Feature);
 
       NearMissesOut.emplace_back(Message);
 

diff  --git a/llvm/lib/Target/CSKY/AsmParser/CSKYAsmParser.cpp b/llvm/lib/Target/CSKY/AsmParser/CSKYAsmParser.cpp
index 1feb24999b504..0b689e62d01b4 100644
--- a/llvm/lib/Target/CSKY/AsmParser/CSKYAsmParser.cpp
+++ b/llvm/lib/Target/CSKY/AsmParser/CSKYAsmParser.cpp
@@ -675,11 +675,9 @@ bool CSKYAsmParser::matchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
     assert(MissingFeatures.any() && "Unknown missing features!");
     ListSeparator LS;
     std::string Msg = "instruction requires the following: ";
-    for (unsigned i = 0, e = MissingFeatures.size(); i != e; ++i) {
-      if (MissingFeatures[i]) {
-        Msg += LS;
-        Msg += getSubtargetFeatureName(i);
-      }
+    for (unsigned Feature : MissingFeatures) {
+      Msg += LS;
+      Msg += getSubtargetFeatureName(Feature);
     }
     return Error(IDLoc, Msg);
   }

diff  --git a/llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp b/llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp
index 5dbd849bdbfe3..ed884e381efab 100644
--- a/llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp
+++ b/llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp
@@ -1795,12 +1795,10 @@ bool LoongArchAsmParser::matchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
     assert(MissingFeatures.any() && "Unknown missing features!");
     bool FirstFeature = true;
     std::string Msg = "instruction requires the following:";
-    for (unsigned i = 0, e = MissingFeatures.size(); i != e; ++i) {
-      if (MissingFeatures[i]) {
-        Msg += FirstFeature ? " " : ", ";
-        Msg += getSubtargetFeatureName(i);
-        FirstFeature = false;
-      }
+    for (unsigned Feature : MissingFeatures) {
+      Msg += FirstFeature ? " " : ", ";
+      Msg += getSubtargetFeatureName(Feature);
+      FirstFeature = false;
     }
     return Error(IDLoc, Msg);
   }

diff  --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
index 384efaae0a025..dd49e24167524 100644
--- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
+++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
@@ -1483,12 +1483,10 @@ bool RISCVAsmParser::matchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
     assert(MissingFeatures.any() && "Unknown missing features!");
     bool FirstFeature = true;
     std::string Msg = "instruction requires the following:";
-    for (unsigned i = 0, e = MissingFeatures.size(); i != e; ++i) {
-      if (MissingFeatures[i]) {
-        Msg += FirstFeature ? " " : ", ";
-        Msg += getSubtargetFeatureName(i);
-        FirstFeature = false;
-      }
+    for (unsigned Feature : MissingFeatures) {
+      Msg += FirstFeature ? " " : ", ";
+      Msg += getSubtargetFeatureName(Feature);
+      FirstFeature = false;
     }
     return Error(IDLoc, Msg);
   }

diff  --git a/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp b/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp
index 45aff90a9998c..5fce852c649a9 100644
--- a/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp
+++ b/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp
@@ -4314,10 +4314,8 @@ bool X86AsmParser::ErrorMissingFeature(SMLoc IDLoc,
   SmallString<126> Msg;
   raw_svector_ostream OS(Msg);
   OS << "instruction requires:";
-  for (unsigned i = 0, e = MissingFeatures.size(); i != e; ++i) {
-    if (MissingFeatures[i])
-      OS << ' ' << getSubtargetFeatureName(i);
-  }
+  for (unsigned Feature : MissingFeatures)
+    OS << ' ' << getSubtargetFeatureName(Feature);
   return Error(IDLoc, OS.str(), SMRange(), MatchingInlineAsm);
 }
 

diff  --git a/llvm/unittests/TargetParser/TargetParserTest.cpp b/llvm/unittests/TargetParser/TargetParserTest.cpp
index 77dede040e440..9e35e70fb40de 100644
--- a/llvm/unittests/TargetParser/TargetParserTest.cpp
+++ b/llvm/unittests/TargetParser/TargetParserTest.cpp
@@ -17,6 +17,7 @@
 #include "llvm/TargetParser/AArch64TargetParser.h"
 #include "llvm/TargetParser/ARMTargetParser.h"
 #include "llvm/TargetParser/ARMTargetParserCommon.h"
+#include "llvm/TargetParser/SubtargetFeature.h"
 #include "llvm/TargetParser/Triple.h"
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
@@ -535,6 +536,36 @@ INSTANTIATE_TEST_SUITE_P(
 
 static constexpr unsigned NumARMCPUArchs = 95;
 
+TEST(FeatureBitsetTest, Iterator) {
+  // Empty bitset yields nothing.
+  FeatureBitset Empty;
+  EXPECT_EQ(Empty.begin(), Empty.end());
+  for (unsigned Index : Empty) {
+    (void)Index;
+    FAIL() << "empty bitset should yield no set bits";
+  }
+
+  // Yields the set indices in order, crossing the 63/64 word boundary.
+  FeatureBitset Bits;
+  Bits.set(0).set(5).set(63).set(64).set(200);
+  std::vector<unsigned> SetIndices;
+  for (unsigned Index : Bits)
+    SetIndices.push_back(Index);
+  EXPECT_EQ(SetIndices, (std::vector<unsigned>{0, 5, 63, 64, 200}));
+
+  // Every yielded index is set, and the count matches.
+  for (unsigned Index : Bits)
+    EXPECT_TRUE(Bits[Index]);
+  EXPECT_EQ(SetIndices.size(), Bits.count());
+
+  // The final position is reached.
+  FeatureBitset Last;
+  unsigned LastIndex = Last.size() - 1;
+  Last.set(LastIndex);
+  SetIndices.assign(Last.begin(), Last.end());
+  EXPECT_EQ(SetIndices, (std::vector<unsigned>{LastIndex}));
+}
+
 TEST(TargetParserTest, testARMCPUArchList) {
   SmallVector<StringRef, NumARMCPUArchs> List;
   ARM::fillValidCPUArchList(List);


        


More information about the llvm-commits mailing list