From e9e53cc5cc0fe092d658751ffa77aae74a8896ee Mon Sep 17 00:00:00 2001 From: David Spickett Date: Fri, 10 Oct 2025 09:26:50 +0000 Subject: [PATCH] [llvm][ADT] Fix uint64_t array BitSet construction on 32-bit systems 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. 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. --- llvm/include/llvm/ADT/Bitset.h | 11 ++++++++--- llvm/unittests/ADT/BitsetTest.cpp | 27 +++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 3 deletions(-) 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(Elt); - Bits[2 * I + 1] = static_cast(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(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 { 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 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 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