[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