[llvm] [APInt] Added APInt::clearBits() method (PR #137098)
Liam Semeria via llvm-commits
llvm-commits at lists.llvm.org
Thu Apr 24 19:11:50 PDT 2025
https://github.com/liamsemeria updated https://github.com/llvm/llvm-project/pull/137098
>From a17519aa401e1488a12481e4495f2c3192852fc5 Mon Sep 17 00:00:00 2001
From: Liam <liamsemeria at gmail.com>
Date: Wed, 23 Apr 2025 17:30:42 -0700
Subject: [PATCH 1/3] [APInt] Added APInt::clearBits() method issue #136550
---
llvm/include/llvm/ADT/APInt.h | 23 +++++++++++++
llvm/lib/Support/APInt.cpp | 27 +++++++++++++++
llvm/unittests/ADT/APIntTest.cpp | 56 ++++++++++++++++++++++++++++++++
3 files changed, 106 insertions(+)
diff --git a/llvm/include/llvm/ADT/APInt.h b/llvm/include/llvm/ADT/APInt.h
index 02d58d8c3d31c..c724411261388 100644
--- a/llvm/include/llvm/ADT/APInt.h
+++ b/llvm/include/llvm/ADT/APInt.h
@@ -1413,6 +1413,26 @@ class [[nodiscard]] APInt {
U.pVal[whichWord(BitPosition)] &= Mask;
}
+ /// Clear the bits from loBit (inclusive) to hiBit (exclusive) to 0.
+ /// This function handles case when \p loBit <= \p hiBit.
+ void clearBits(unsigned loBit, unsigned hiBit) {
+ assert(hiBit <= BitWidth && "hiBit out of range");
+ assert(loBit <= BitWidth && "loBit out of range");
+ assert(loBit <= hiBit && "loBit greater than hiBit");
+ if (loBit == hiBit)
+ return;
+ if (loBit < APINT_BITS_PER_WORD && hiBit <= APINT_BITS_PER_WORD) {
+ uint64_t mask = WORDTYPE_MAX >> (APINT_BITS_PER_WORD - (hiBit - loBit));
+ mask = ~(mask << loBit);
+ if (isSingleWord())
+ U.VAL &= mask;
+ else
+ U.pVal[0] &= mask;
+ } else {
+ clearBitsSlowCase(loBit, hiBit);
+ }
+ }
+
/// Set bottom loBits bits to 0.
void clearLowBits(unsigned loBits) {
assert(loBits <= BitWidth && "More bits than bitwidth");
@@ -2051,6 +2071,9 @@ class [[nodiscard]] APInt {
/// out-of-line slow case for setBits.
void setBitsSlowCase(unsigned loBit, unsigned hiBit);
+ /// out-of-line slow case for clearBits.
+ void clearBitsSlowCase(unsigned loBit, unsigned hiBit);
+
/// out-of-line slow case for flipAllBits.
void flipAllBitsSlowCase();
diff --git a/llvm/lib/Support/APInt.cpp b/llvm/lib/Support/APInt.cpp
index 4e45416b4598f..da7f223d48956 100644
--- a/llvm/lib/Support/APInt.cpp
+++ b/llvm/lib/Support/APInt.cpp
@@ -336,6 +336,33 @@ void APInt::setBitsSlowCase(unsigned loBit, unsigned hiBit) {
U.pVal[word] = WORDTYPE_MAX;
}
+void APInt::clearBitsSlowCase(unsigned loBit, unsigned hiBit) {
+ unsigned loWord = whichWord(loBit);
+ unsigned hiWord = whichWord(hiBit);
+
+ // Create an initial mask for the low word with ones below loBit.
+ uint64_t loMask = ~(WORDTYPE_MAX << whichBit(loBit));
+
+ // If hiBit is not aligned, we need a high mask.
+ unsigned hiShiftAmt = whichBit(hiBit);
+ if (hiShiftAmt != 0) {
+ // Create a high mask with ones above hiBit.
+ uint64_t hiMask = ~(WORDTYPE_MAX >> (APINT_BITS_PER_WORD - hiShiftAmt));
+ // If loWord and hiWord are equal, then we combine the masks. Otherwise,
+ // set the bits in hiWord.
+ if (hiWord == loWord)
+ loMask &= hiMask;
+ else
+ U.pVal[hiWord] &= hiMask;
+ }
+ // Apply the mask to the low word.
+ U.pVal[loWord] &= loMask;
+
+ // Fill any words between loWord and hiWord with all zeros.
+ for (unsigned word = loWord + 1; word < hiWord; ++word)
+ U.pVal[word] = 0;
+}
+
// Complement a bignum in-place.
static void tcComplement(APInt::WordType *dst, unsigned parts) {
for (unsigned i = 0; i < parts; i++)
diff --git a/llvm/unittests/ADT/APIntTest.cpp b/llvm/unittests/ADT/APIntTest.cpp
index b14366eac2185..d4411dfe36cc9 100644
--- a/llvm/unittests/ADT/APIntTest.cpp
+++ b/llvm/unittests/ADT/APIntTest.cpp
@@ -2520,6 +2520,62 @@ TEST(APIntTest, setAllBits) {
EXPECT_EQ(128u, i128.popcount());
}
+TEST(APIntTest, clearBits) {
+ APInt i32 = APInt::getAllOnes(32);
+ i32.clearBits(1, 3);
+ EXPECT_EQ(1u, i32.countr_one());
+ EXPECT_EQ(0u, i32.countr_zero());
+ EXPECT_EQ(32u, i32.getActiveBits());
+ EXPECT_EQ(0u, i32.countl_zero());
+ EXPECT_EQ(29u, i32.countl_one());
+ EXPECT_EQ(30u, i32.popcount());
+
+ i32.clearBits(15, 15);
+ EXPECT_EQ(1u, i32.countr_one());
+ EXPECT_EQ(0u, i32.countr_zero());
+ EXPECT_EQ(32u, i32.getActiveBits());
+ EXPECT_EQ(0u, i32.countl_zero());
+ EXPECT_EQ(29u, i32.countl_one());
+ EXPECT_EQ(30u, i32.popcount());
+
+ i32.clearBits(28, 31);
+ EXPECT_EQ(1u, i32.countr_one());
+ EXPECT_EQ(0u, i32.countr_zero());
+ EXPECT_EQ(32u, i32.getActiveBits());
+ EXPECT_EQ(0u, i32.countl_zero());
+ EXPECT_EQ(1u, i32.countl_one());
+ EXPECT_EQ(27u, i32.popcount());
+ EXPECT_EQ(static_cast<uint64_t>((1 << 31) | ((~0u >> 4) & (~0u << 3)) | 1),
+ i32.getZExtValue());
+
+ APInt i256 = APInt::getAllOnes(256);
+ i256.clearBits(10, 250);
+ EXPECT_EQ(10u, i256.countr_one());
+ EXPECT_EQ(0u, i256.countr_zero());
+ EXPECT_EQ(256u, i256.getActiveBits());
+ EXPECT_EQ(0u, i256.countl_zero());
+ EXPECT_EQ(6u, i256.countl_one());
+ EXPECT_EQ(16u, i256.popcount());
+
+ APInt i64hi32 = APInt::getAllOnes(64);
+ i64hi32.clearBits(0, 32);
+ EXPECT_EQ(32u, i64hi32.countl_one());
+ EXPECT_EQ(0u, i64hi32.countl_zero());
+ EXPECT_EQ(64u, i64hi32.getActiveBits());
+ EXPECT_EQ(32u, i64hi32.countr_zero());
+ EXPECT_EQ(0u, i64hi32.countr_one());
+ EXPECT_EQ(32u, i64hi32.popcount());
+
+ i64hi32 = APInt::getAllOnes(64);
+ i64hi32.clearBits(32, 64);
+ EXPECT_EQ(32u, i64hi32.countr_one());
+ EXPECT_EQ(0u, i64hi32.countr_zero());
+ EXPECT_EQ(32u, i64hi32.getActiveBits());
+ EXPECT_EQ(32u, i64hi32.countl_zero());
+ EXPECT_EQ(0u, i64hi32.countl_one());
+ EXPECT_EQ(32u, i64hi32.popcount());
+}
+
TEST(APIntTest, getLoBits) {
APInt i32(32, 0xfa);
i32.setHighBits(1);
>From bbf8c1644c63ab97fc71622f8b169e56fcf9a69e Mon Sep 17 00:00:00 2001
From: Liam <liamsemeria at gmail.com>
Date: Thu, 24 Apr 2025 16:52:24 -0700
Subject: [PATCH 2/3] updated AP::IntCLearBits test
---
llvm/unittests/ADT/APIntTest.cpp | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/llvm/unittests/ADT/APIntTest.cpp b/llvm/unittests/ADT/APIntTest.cpp
index d4411dfe36cc9..a58fbd6deffa5 100644
--- a/llvm/unittests/ADT/APIntTest.cpp
+++ b/llvm/unittests/ADT/APIntTest.cpp
@@ -2545,8 +2545,7 @@ TEST(APIntTest, clearBits) {
EXPECT_EQ(0u, i32.countl_zero());
EXPECT_EQ(1u, i32.countl_one());
EXPECT_EQ(27u, i32.popcount());
- EXPECT_EQ(static_cast<uint64_t>((1 << 31) | ((~0u >> 4) & (~0u << 3)) | 1),
- i32.getZExtValue());
+ EXPECT_EQ(APInt(32, "8FFFFFF9", 16), i32);
APInt i256 = APInt::getAllOnes(256);
i256.clearBits(10, 250);
@@ -2557,6 +2556,15 @@ TEST(APIntTest, clearBits) {
EXPECT_EQ(6u, i256.countl_one());
EXPECT_EQ(16u, i256.popcount());
+ APInt i311 = APInt::getAllOnes(311);
+ i311.clearBits(33, 99);
+ EXPECT_EQ(33u, i311.countr_one());
+ EXPECT_EQ(0u, i311.countr_zero());
+ EXPECT_EQ(311u, i311.getActiveBits());
+ EXPECT_EQ(0u, i311.countl_zero());
+ EXPECT_EQ(212u, i311.countl_one());
+ EXPECT_EQ(245u, i311.popcount());
+
APInt i64hi32 = APInt::getAllOnes(64);
i64hi32.clearBits(0, 32);
EXPECT_EQ(32u, i64hi32.countl_one());
>From 6700a18d7258093bc52ede3da6c9f977abe6d66a Mon Sep 17 00:00:00 2001
From: Liam <liamsemeria at gmail.com>
Date: Thu, 24 Apr 2025 19:11:33 -0700
Subject: [PATCH 3/3] replaced APInt::insertBits with APInt::clearBits for
demanded elts handling
---
llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 4 ++--
llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 0a2687a16a80c..cf0824b641d0c 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -3547,7 +3547,7 @@ KnownBits SelectionDAG::computeKnownBits(SDValue Op, const APInt &DemandedElts,
unsigned NumSubElts = Sub.getValueType().getVectorNumElements();
APInt DemandedSubElts = DemandedElts.extractBits(NumSubElts, Idx);
APInt DemandedSrcElts = DemandedElts;
- DemandedSrcElts.insertBits(APInt::getZero(NumSubElts), Idx);
+ DemandedSrcElts.clearBits(Idx, Idx + NumSubElts);
Known.One.setAllBits();
Known.Zero.setAllBits();
@@ -5202,7 +5202,7 @@ unsigned SelectionDAG::ComputeNumSignBits(SDValue Op, const APInt &DemandedElts,
unsigned NumSubElts = Sub.getValueType().getVectorNumElements();
APInt DemandedSubElts = DemandedElts.extractBits(NumSubElts, Idx);
APInt DemandedSrcElts = DemandedElts;
- DemandedSrcElts.insertBits(APInt::getZero(NumSubElts), Idx);
+ DemandedSrcElts.clearBits(Idx, Idx + NumSubElts);
Tmp = std::numeric_limits<unsigned>::max();
if (!!DemandedSubElts) {
diff --git a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
index 6930b54ddb14a..514ef9190f714 100644
--- a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
@@ -1290,7 +1290,7 @@ bool TargetLowering::SimplifyDemandedBits(
unsigned NumSubElts = Sub.getValueType().getVectorNumElements();
APInt DemandedSubElts = DemandedElts.extractBits(NumSubElts, Idx);
APInt DemandedSrcElts = DemandedElts;
- DemandedSrcElts.insertBits(APInt::getZero(NumSubElts), Idx);
+ DemandedSrcElts.clearBits(Idx, Idx + NumSubElts);
KnownBits KnownSub, KnownSrc;
if (SimplifyDemandedBits(Sub, DemandedBits, DemandedSubElts, KnownSub, TLO,
@@ -3357,7 +3357,7 @@ bool TargetLowering::SimplifyDemandedVectorElts(
unsigned NumSubElts = Sub.getValueType().getVectorNumElements();
APInt DemandedSubElts = DemandedElts.extractBits(NumSubElts, Idx);
APInt DemandedSrcElts = DemandedElts;
- DemandedSrcElts.insertBits(APInt::getZero(NumSubElts), Idx);
+ DemandedSrcElts.clearBits(Idx, Idx + NumSubElts);
APInt SubUndef, SubZero;
if (SimplifyDemandedVectorElts(Sub, DemandedSubElts, SubUndef, SubZero, TLO,
More information about the llvm-commits
mailing list