[llvm] [APInt] Added APInt::clearBits() method (PR #137098)

Liam Semeria via llvm-commits llvm-commits at lists.llvm.org
Sun May 18 12:05:32 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/6] [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/6] 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/6] 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,

>From e85f09c011ad4433c745a924a868731de148f475 Mon Sep 17 00:00:00 2001
From: Liam <liamsemeria at gmail.com>
Date: Mon, 12 May 2025 11:59:06 -0700
Subject: [PATCH 4/6] APInt::clearBits updated to match APInt::setBits changes

---
 llvm/include/llvm/ADT/APInt.h | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/llvm/include/llvm/ADT/APInt.h b/llvm/include/llvm/ADT/APInt.h
index c724411261388..da39ed748a6b4 100644
--- a/llvm/include/llvm/ADT/APInt.h
+++ b/llvm/include/llvm/ADT/APInt.h
@@ -1417,11 +1417,10 @@ class [[nodiscard]] APInt {
   /// 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) {
+    if (hiBit <= APINT_BITS_PER_WORD) {
       uint64_t mask = WORDTYPE_MAX >> (APINT_BITS_PER_WORD - (hiBit - loBit));
       mask = ~(mask << loBit);
       if (isSingleWord())

>From 2d8fa9d6995327bceed760719235b2a1d9f93578 Mon Sep 17 00:00:00 2001
From: Liam <liamsemeria at gmail.com>
Date: Wed, 14 May 2025 20:30:58 -0700
Subject: [PATCH 5/6] changed capitalization for APInt::clearbits

---
 llvm/include/llvm/ADT/APInt.h | 20 ++++++++++----------
 llvm/lib/Support/APInt.cpp    | 26 +++++++++++++-------------
 2 files changed, 23 insertions(+), 23 deletions(-)

diff --git a/llvm/include/llvm/ADT/APInt.h b/llvm/include/llvm/ADT/APInt.h
index da39ed748a6b4..b93590ec4cc79 100644
--- a/llvm/include/llvm/ADT/APInt.h
+++ b/llvm/include/llvm/ADT/APInt.h
@@ -1415,20 +1415,20 @@ class [[nodiscard]] APInt {
 
   /// 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 <= hiBit && "loBit greater than hiBit");
-    if (loBit == hiBit)
+  void clearBits(unsigned LoBit, unsigned HiBit) {
+    assert(HiBit <= BitWidth && "hiBit out of range");
+    assert(LoBit <= HiBit && "loBit greater than hiBit");
+    if (LoBit == HiBit)
       return;
-    if (hiBit <= APINT_BITS_PER_WORD) {
-      uint64_t mask = WORDTYPE_MAX >> (APINT_BITS_PER_WORD - (hiBit - loBit));
-      mask = ~(mask << loBit);
+    if (HiBit <= APINT_BITS_PER_WORD) {
+      uint64_t Mask = WORDTYPE_MAX >> (APINT_BITS_PER_WORD - (HiBit - LoBit));
+      Mask = ~(Mask << LoBit);
       if (isSingleWord())
-        U.VAL &= mask;
+        U.VAL &= Mask;
       else
-        U.pVal[0] &= mask;
+        U.pVal[0] &= Mask;
     } else {
-      clearBitsSlowCase(loBit, hiBit);
+      clearBitsSlowCase(LoBit, HiBit);
     }
   }
 
diff --git a/llvm/lib/Support/APInt.cpp b/llvm/lib/Support/APInt.cpp
index da7f223d48956..6879e6ba17762 100644
--- a/llvm/lib/Support/APInt.cpp
+++ b/llvm/lib/Support/APInt.cpp
@@ -336,31 +336,31 @@ 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);
+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));
+  uint64_t LoMask = ~(WORDTYPE_MAX << whichBit(LoBit));
 
   // If hiBit is not aligned, we need a high mask.
-  unsigned hiShiftAmt = whichBit(hiBit);
-  if (hiShiftAmt != 0) {
+  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));
+    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;
+    if (HiWord == LoWord)
+      LoMask &= HiMask;
     else
-      U.pVal[hiWord] &= hiMask;
+      U.pVal[HiWord] &= HiMask;
   }
   // Apply the mask to the low word.
-  U.pVal[loWord] &= loMask;
+  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;
+  for (unsigned Word = LoWord + 1; Word < HiWord; ++Word)
+    U.pVal[Word] = 0;
 }
 
 // Complement a bignum in-place.

>From cfbf324cafa81ce2b9cadd21963218cdf97c1389 Mon Sep 17 00:00:00 2001
From: Liam <liamsemeria at gmail.com>
Date: Sun, 18 May 2025 12:05:11 -0700
Subject: [PATCH 6/6] changed more capitalization

---
 llvm/include/llvm/ADT/APInt.h | 10 +++++-----
 llvm/lib/Support/APInt.cpp    | 10 +++++-----
 2 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/llvm/include/llvm/ADT/APInt.h b/llvm/include/llvm/ADT/APInt.h
index b93590ec4cc79..02bc932fb0a61 100644
--- a/llvm/include/llvm/ADT/APInt.h
+++ b/llvm/include/llvm/ADT/APInt.h
@@ -1413,11 +1413,11 @@ 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.
+  /// 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 <= HiBit && "loBit greater than hiBit");
+    assert(HiBit <= BitWidth && "HiBit out of range");
+    assert(LoBit <= HiBit && "LoBit greater than HiBit");
     if (LoBit == HiBit)
       return;
     if (HiBit <= APINT_BITS_PER_WORD) {
@@ -2071,7 +2071,7 @@ class [[nodiscard]] APInt {
   void setBitsSlowCase(unsigned loBit, unsigned hiBit);
 
   /// out-of-line slow case for clearBits.
-  void clearBitsSlowCase(unsigned loBit, unsigned hiBit);
+  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 6879e6ba17762..0119cb2f6e1f7 100644
--- a/llvm/lib/Support/APInt.cpp
+++ b/llvm/lib/Support/APInt.cpp
@@ -343,13 +343,13 @@ void APInt::clearBitsSlowCase(unsigned LoBit, unsigned 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.
+  // 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.
+    // 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 LoWord and HiWord are equal, then we combine the masks. Otherwise,
+    // set the bits in HiWord.
     if (HiWord == LoWord)
       LoMask &= HiMask;
     else
@@ -358,7 +358,7 @@ void APInt::clearBitsSlowCase(unsigned LoBit, unsigned HiBit) {
   // Apply the mask to the low word.
   U.pVal[LoWord] &= LoMask;
 
-  // Fill any words between loWord and hiWord with all zeros.
+  // Fill any words between LoWord and HiWord with all zeros.
   for (unsigned Word = LoWord + 1; Word < HiWord; ++Word)
     U.pVal[Word] = 0;
 }



More information about the llvm-commits mailing list