[llvm] 6f1ce2b - [llvm][ADT] Fix uint64_t array BitSet construction on 32-bit systems (#162814)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Oct 10 03:08:54 PDT 2025
Author: David Spickett
Date: 2025-10-10T10:08:50Z
New Revision: 6f1ce2b25b56d0fac317d93e7b59a22afbb54931
URL: https://github.com/llvm/llvm-project/commit/6f1ce2b25b56d0fac317d93e7b59a22afbb54931
DIFF: https://github.com/llvm/llvm-project/commit/6f1ce2b25b56d0fac317d93e7b59a22afbb54931.diff
LOG: [llvm][ADT] Fix uint64_t array BitSet construction on 32-bit systems (#162814)
When the underlying storage element is 32-bit, we may only need half of
the last value in the uint64_t array. I've adjusted the constructor to
account for that.
For example, if you construct a 65 bit bitset you will need both 32-bit
halves of the first array value but only the bottom half of the second
value. The storage will only have 3 elements, so attempting to assign
the top 32-bits into the storage will fail.
This happened on our buildbot:
https://lab.llvm.org/buildbot/#/builders/154/builds/22555
(though the traceback is not useful)
Then added tests for < 32 bit sizes, and assertions for the number of
elements we decide to use. Given that the only member of BitSet is a
std::array, I think the size will be consistent across systems.
Tested on 32 and 64-bit Arm machines.
Follow up to #162703.
Added:
Modified:
llvm/include/llvm/ADT/Bitset.h
llvm/unittests/ADT/BitsetTest.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/ADT/Bitset.h b/llvm/include/llvm/ADT/Bitset.h
index 0dfeb2088dfa0..1d4cbf8306230 100644
--- a/llvm/include/llvm/ADT/Bitset.h
+++ b/llvm/include/llvm/ADT/Bitset.h
@@ -47,10 +47,15 @@ class Bitset {
for (size_t I = 0; I != B.size(); ++I)
Bits[I] = B[I];
} else {
- for (size_t I = 0; I != B.size(); ++I) {
+ unsigned BitsToAssign = NumBits;
+ for (size_t I = 0; I != B.size() && BitsToAssign; ++I) {
uint64_t Elt = B[I];
- Bits[2 * I] = static_cast<uint32_t>(Elt);
- Bits[2 * I + 1] = static_cast<uint32_t>(Elt >> 32);
+ // On a 32-bit system the storage type will be 32-bit, so we may only
+ // need half of a uint64_t.
+ for (size_t offset = 0; offset != 2 && BitsToAssign; ++offset) {
+ Bits[2 * I + offset] = static_cast<uint32_t>(Elt >> (32 * offset));
+ BitsToAssign = BitsToAssign >= 32 ? BitsToAssign - 32 : 0;
+ }
}
}
}
diff --git a/llvm/unittests/ADT/BitsetTest.cpp b/llvm/unittests/ADT/BitsetTest.cpp
index 8877397b30c53..0ecd213d6a781 100644
--- a/llvm/unittests/ADT/BitsetTest.cpp
+++ b/llvm/unittests/ADT/BitsetTest.cpp
@@ -31,14 +31,41 @@ class TestBitsetUInt64Array : public Bitset<NumBits> {
return true;
}
+
+ void verifyStorageSize(size_t elements_64_bit, size_t elements_32_bit) {
+ if constexpr (sizeof(uintptr_t) == sizeof(uint64_t))
+ EXPECT_EQ(sizeof(*this), elements_64_bit * sizeof(uintptr_t));
+ else
+ EXPECT_EQ(sizeof(*this), elements_32_bit * sizeof(uintptr_t));
+ }
};
TEST(BitsetTest, Construction) {
std::array<uint64_t, 2> TestVals = {0x123456789abcdef3, 0x1337d3a0b22c24};
TestBitsetUInt64Array<96> Test(TestVals);
EXPECT_TRUE(Test.verifyValue(TestVals));
+ Test.verifyStorageSize(2, 3);
TestBitsetUInt64Array<65> Test1(TestVals);
EXPECT_TRUE(Test1.verifyValue(TestVals));
+ Test1.verifyStorageSize(2, 3);
+
+ std::array<uint64_t, 1> TestSingleVal = {0x12345678abcdef99};
+
+ TestBitsetUInt64Array<64> Test64(TestSingleVal);
+ EXPECT_TRUE(Test64.verifyValue(TestSingleVal));
+ Test64.verifyStorageSize(1, 2);
+
+ TestBitsetUInt64Array<30> Test30(TestSingleVal);
+ EXPECT_TRUE(Test30.verifyValue(TestSingleVal));
+ Test30.verifyStorageSize(1, 1);
+
+ TestBitsetUInt64Array<32> Test32(TestSingleVal);
+ EXPECT_TRUE(Test32.verifyValue(TestSingleVal));
+ Test32.verifyStorageSize(1, 1);
+
+ TestBitsetUInt64Array<33> Test33(TestSingleVal);
+ EXPECT_TRUE(Test33.verifyValue(TestSingleVal));
+ Test33.verifyStorageSize(1, 2);
}
} // namespace
More information about the llvm-commits
mailing list