[llvm] [Analysis] Improve readability of `KnownBits::pext` and `KnownBits::pdep` (PR #205176)

Simon Pilgrim via llvm-commits llvm-commits at lists.llvm.org
Sat Jun 27 04:00:48 PDT 2026


https://github.com/RKSimon updated https://github.com/llvm/llvm-project/pull/205176

>From 141d521e03e807cc6f4b6172ed34066674621c37 Mon Sep 17 00:00:00 2001
From: Eisenwave <me at eisenwave.net>
Date: Mon, 22 Jun 2026 21:43:10 +0200
Subject: [PATCH 1/2] [Analysis] Improve readability of KnownBits::pext and
 KnownBits::pdep

- Change the parameter names to Val and Mask to emphasize their semantics.
- Use clearBits instead of bitwise AND for increased expressiveness.
- Rewrite explanatory comments.
---
 llvm/include/llvm/Support/KnownBits.h |  8 +--
 llvm/lib/Support/KnownBits.cpp        | 81 ++++++++++++++-------------
 2 files changed, 46 insertions(+), 43 deletions(-)

diff --git a/llvm/include/llvm/Support/KnownBits.h b/llvm/include/llvm/Support/KnownBits.h
index dc80a3f10b087..f88e5bdd1a92d 100644
--- a/llvm/include/llvm/Support/KnownBits.h
+++ b/llvm/include/llvm/Support/KnownBits.h
@@ -479,11 +479,11 @@ struct KnownBits {
   /// Compute known bits for clmul(LHS, RHS).
   LLVM_ABI static KnownBits clmul(const KnownBits &LHS, const KnownBits &RHS);
 
-  /// Compute known bits for pext(LHS, RHS).
-  LLVM_ABI static KnownBits pext(const KnownBits &LHS, const KnownBits &RHS);
+  /// Compute known bits for pext(Val, Mask).
+  LLVM_ABI static KnownBits pext(const KnownBits &Val, const KnownBits &Mask);
 
-  /// Compute known bits for pdep(LHS, RHS).
-  LLVM_ABI static KnownBits pdep(const KnownBits &LHS, const KnownBits &RHS);
+  /// Compute known bits for pdep(Val, Mask).
+  LLVM_ABI static KnownBits pdep(const KnownBits &Val, const KnownBits &Mask);
 
   /// Determine if these known bits always give the same ICMP_EQ result.
   LLVM_ABI static std::optional<bool> eq(const KnownBits &LHS,
diff --git a/llvm/lib/Support/KnownBits.cpp b/llvm/lib/Support/KnownBits.cpp
index a2f71061fe0ad..8dda7506a271b 100644
--- a/llvm/lib/Support/KnownBits.cpp
+++ b/llvm/lib/Support/KnownBits.cpp
@@ -645,66 +645,69 @@ KnownBits KnownBits::clmul(const KnownBits &LHS, const KnownBits &RHS) {
   return Res;
 }
 
-KnownBits KnownBits::pext(const KnownBits &LHS, const KnownBits &RHS) {
-  // For each source position I where mask[I] could be set, the output index j
-  // lies in [M0, M1] where these track the range of possible set-bit counts
-  // seen so far in mask.
-  //
-  // The output bit j
-  // - can be 0 if any candidate LHS[I] could be zero or popcount(mask) could
-  //   be <= j, and
-  // - can be 1 only if some candidate LHS[I] could be one and popcount(mask)
-  //   is known > j.
-  unsigned BitWidth = LHS.getBitWidth();
+KnownBits KnownBits::pext(const KnownBits &Val, const KnownBits &Mask) {
+  unsigned BitWidth = Val.getBitWidth();
   KnownBits Res(BitWidth);
+  // We start by asserting that bits cannot be 0 and cannot be 1, then clear
+  // Res bits where we know a bit could have some value.
   Res.setAllConflict();
 
+  // For each source position I where Mask[I] could be 1, the output position J
+  // lies in [M0, M1], where M0 and M1 track the range of possible 1-bit counts
+  // seen so far in Mask. Note that M0=M1 as long as bits in Mask are known;
+  // otherwise, the range of possible output positions widens.
   unsigned M0 = 0, M1 = 0;
   for (unsigned I = 0; I < BitWidth; ++I) {
-    if (!RHS.Zero[I]) {
-      APInt Range = APInt::getBitsSet(BitWidth, M0, M1 + 1);
-      if (!LHS.Zero[I])
-        Res.Zero &= ~Range; // some position in Range could be 1
-      if (!LHS.One[I])
-        Res.One &= ~Range; // some position in Range could be 0
+    if (!Mask.Zero[I]) {
+      // Mask[I] could be 1, so we decide what value the Res bits could have.
+      if (!Val.Zero[I])
+        // Val[I] could be 1 => Res[J] for J in [M0, M1] could be 1
+        Res.Zero.clearBits(M0, M1 + 1);
+      if (!Val.One[I])
+        // Val[I] could be 0 => Res[J] for J in [M0, M1] could be 0
+        Res.One.clearBits(M0, M1 + 1);
     }
-    if (RHS.One[I])
+    if (Mask.One[I])
       ++M0, ++M1;
-    else if (!RHS.Zero[I])
+    else if (!Mask.Zero[I])
       ++M1;
   }
 
-  // Output positions j >= M0 may have no source (popcount(mask) <= j), in
-  // which case they default to zero.
-  Res.One &= APInt::getLowBitsSet(BitWidth, M0);
+  // Output bits at J >= M0 have no source (popcount(RHS) <= J), in
+  // which case they default to 0.
+  Res.One.clearBits(M0, BitWidth);
   return Res;
 }
 
-KnownBits KnownBits::pdep(const KnownBits &LHS, const KnownBits &RHS) {
-  // For each output position I where mask[I] could be set, the source index j
-  // lies in [M0, M1] where these track possible counts of set mask bits < I.
-  //
-  // The output bit
-  // - can be 0 if mask[I] or any candidate LHS[j] could be zero, and
-  // - can be 1 only if both mask[I] and some candidate LHS[j] could be one.
-  unsigned BitWidth = LHS.getBitWidth();
+KnownBits KnownBits::pdep(const KnownBits &Val, const KnownBits &Mask) {
+  unsigned BitWidth = Val.getBitWidth();
   KnownBits Res(BitWidth);
+  // We start by asserting that bits cannot be 0 and cannot be 1, then clear
+  // Res bits where we know a bit could have some value.
   Res.setAllConflict();
 
+  // For each output position I where Mask[I] could be 1, the source position J
+  // lies in [M0, M1], where M0 and M1 track the range of possible 1-bit counts
+  // seen so far in Mask. Note that M0=M1 as long as bits in Mask are known;
+  // otherwise, the range of possible source positions widens.
   unsigned M0 = 0, M1 = 0;
   for (unsigned I = 0; I < BitWidth; ++I) {
-    if (!RHS.One[I])
-      Res.One.clearBit(I); // mask[I] could be 0 -> output[I] could be 0
-    if (!RHS.Zero[I]) {
+    if (!Mask.One[I])
+      // Mask[I] could be 0 => Res[I] could be 0
+      Res.One.clearBit(I);
+    if (!Mask.Zero[I]) {
+      // Mask[I] could be 1, so we check what value the Val bits could have.
       APInt Range = APInt::getBitsSet(BitWidth, M0, M1 + 1);
-      if (!Range.isSubsetOf(LHS.One))
-        Res.One.clearBit(I); // some candidate could be 0
-      if (!Range.isSubsetOf(LHS.Zero))
-        Res.Zero.clearBit(I); // some candidate could be 1
+      if (!Range.isSubsetOf(Val.One))
+        // Any Val[J] for J in [M0, M1] could be 0 => Res[I] could be 0
+        Res.One.clearBit(I);
+      if (!Range.isSubsetOf(Val.Zero))
+        // Any Val[J] for J in [M0, M1] could be 1 => Res[I] could be 1
+        Res.Zero.clearBit(I);
     }
-    if (RHS.One[I])
+    if (Mask.One[I])
       ++M0, ++M1;
-    else if (!RHS.Zero[I])
+    else if (!Mask.Zero[I])
       ++M1;
   }
   return Res;

>From 4dac451e32657cba24a6b17d8d51b8da330a3cfc Mon Sep 17 00:00:00 2001
From: Jan Schultke <me at eisenwave.net>
Date: Tue, 23 Jun 2026 11:50:04 +0200
Subject: [PATCH 2/2] Apply suggestion from @jayfoad

Co-authored-by: Jay Foad <jay.foad at gmail.com>
---
 llvm/lib/Support/KnownBits.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Support/KnownBits.cpp b/llvm/lib/Support/KnownBits.cpp
index 8dda7506a271b..d9c588780510c 100644
--- a/llvm/lib/Support/KnownBits.cpp
+++ b/llvm/lib/Support/KnownBits.cpp
@@ -673,8 +673,8 @@ KnownBits KnownBits::pext(const KnownBits &Val, const KnownBits &Mask) {
       ++M1;
   }
 
-  // Output bits at J >= M0 have no source (popcount(RHS) <= J), in
-  // which case they default to 0.
+  // Output bits at J >= M0 may have no source (popcount(Mask) may be <= J), so
+  // they may be 0.
   Res.One.clearBits(M0, BitWidth);
   return Res;
 }



More information about the llvm-commits mailing list