-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[llvm][ADT] Fix uint64_t array BitSet construction on 32-bit systems #162814
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
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/pr-subscribers-llvm-adt Author: David Spickett (DavidSpickett) ChangesWhen 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. Follow up to #162703. Full diff: https://github.com/llvm/llvm-project/pull/162814.diff 2 Files Affected:
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
|
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/116/builds/19538 Here is the relevant piece of the build log for the reference
|
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.