[llvm] [InstCombine] Add additional known bits info for self multiply (PR #151202)
Macsen Casaus via llvm-commits
llvm-commits at lists.llvm.org
Fri Aug 8 17:45:50 PDT 2025
https://github.com/macsencasaus updated https://github.com/llvm/llvm-project/pull/151202
>From 4d0e99052769aeb8f5eb92745dad2733364b0664 Mon Sep 17 00:00:00 2001
From: Macsen Casaus <macsen at fedora.localdomain>
Date: Tue, 29 Jul 2025 10:44:11 -0600
Subject: [PATCH 1/6] pre-commit test
---
.../test/Transforms/InstCombine/known-bits.ll | 56 +++++++++++++++++++
1 file changed, 56 insertions(+)
diff --git a/llvm/test/Transforms/InstCombine/known-bits.ll b/llvm/test/Transforms/InstCombine/known-bits.ll
index 9a9fec694ff0e..3868b5c3701c9 100644
--- a/llvm/test/Transforms/InstCombine/known-bits.ll
+++ b/llvm/test/Transforms/InstCombine/known-bits.ll
@@ -1244,6 +1244,62 @@ define i1 @extract_value_smul_fail(i8 %xx, i8 %yy) {
ret i1 %r
}
+define i8 @known_self_mul_bit_0_set(i8 noundef %x) {
+; CHECK-LABEL: @known_self_mul_bit_0_set(
+; CHECK-NEXT: [[BIT_0_SET:%.*]] = or i8 [[X:%.*]], 1
+; CHECK-NEXT: [[SELF_MUL:%.*]] = mul i8 [[BIT_0_SET]], [[BIT_0_SET]]
+; CHECK-NEXT: [[R:%.*]] = and i8 [[SELF_MUL]], 4
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %bit_0_set = or i8 %x, 1
+ %self_mul = mul i8 %bit_0_set, %bit_0_set
+ %r = and i8 %self_mul, 4
+ ret i8 %r
+}
+
+define i8 @known_self_mul_bit_0_unset(i8 noundef %x) {
+; CHECK-LABEL: @known_self_mul_bit_0_unset(
+; CHECK-NEXT: [[BIT_0_UNSET:%.*]] = and i8 [[X:%.*]], -2
+; CHECK-NEXT: [[SELF_MUL:%.*]] = mul i8 [[BIT_0_UNSET]], [[BIT_0_UNSET]]
+; CHECK-NEXT: [[R:%.*]] = and i8 [[SELF_MUL]], 8
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %bit_0_unset = and i8 %x, -2
+ %self_mul = mul i8 %bit_0_unset, %bit_0_unset
+ %r = and i8 %self_mul, 8
+ ret i8 %r
+}
+
+define i8 @known_self_mul_bit_1_set_bit_0_unset(i8 noundef %x) {
+; CHECK-LABEL: @known_self_mul_bit_1_set_bit_0_unset(
+; CHECK-NEXT: [[LOWER_2_UNSET:%.*]] = and i8 [[X:%.*]], -4
+; CHECK-NEXT: [[BIT_1_SET_BIT_0_UNSET:%.*]] = or disjoint i8 [[LOWER_2_UNSET]], 2
+; CHECK-NEXT: [[SELF_MUL:%.*]] = mul i8 [[BIT_1_SET_BIT_0_UNSET]], [[BIT_1_SET_BIT_0_UNSET]]
+; CHECK-NEXT: [[R:%.*]] = and i8 [[SELF_MUL]], 24
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %lower_2_unset = and i8 %x, -4
+ %bit_1_set_bit_0_unset = or disjoint i8 %lower_2_unset, 2
+ %self_mul = mul i8 %bit_1_set_bit_0_unset, %bit_1_set_bit_0_unset
+ %r = and i8 %self_mul, 24
+ ret i8 %r
+}
+
+define i4 @known_self_mul_bit_1_set_bit_0_unset_i4(i4 noundef %x) {
+; CHECK-LABEL: @known_self_mul_bit_1_set_bit_0_unset_i4(
+; CHECK-NEXT: [[LOWER_2_UNSET:%.*]] = and i4 [[X:%.*]], -4
+; CHECK-NEXT: [[BIT_1_SET_BIT_0_UNSET:%.*]] = or disjoint i4 [[LOWER_2_UNSET]], 2
+; CHECK-NEXT: [[SELF_MUL:%.*]] = mul i4 [[BIT_1_SET_BIT_0_UNSET]], [[BIT_1_SET_BIT_0_UNSET]]
+; CHECK-NEXT: [[R:%.*]] = and i4 [[SELF_MUL]], -8
+; CHECK-NEXT: ret i4 [[R]]
+;
+ %lower_2_unset = and i4 %x, -4
+ %bit_1_set_bit_0_unset = or disjoint i4 %lower_2_unset, 2
+ %self_mul = mul i4 %bit_1_set_bit_0_unset, %bit_1_set_bit_0_unset
+ %r = and i4 %self_mul, 24
+ ret i4 %r
+}
+
define i8 @known_reduce_or(<2 x i8> %xx) {
; CHECK-LABEL: @known_reduce_or(
; CHECK-NEXT: ret i8 1
>From 37dfb4b393979a5aab93ee2de9e102a999654175 Mon Sep 17 00:00:00 2001
From: Macsen Casaus <macsen at fedora.localdomain>
Date: Tue, 29 Jul 2025 10:45:28 -0600
Subject: [PATCH 2/6] Add additional known bits info for self multiply
---
llvm/lib/Support/KnownBits.cpp | 29 +++++++++++++++----
.../test/Transforms/InstCombine/known-bits.ll | 22 +++-----------
2 files changed, 28 insertions(+), 23 deletions(-)
diff --git a/llvm/lib/Support/KnownBits.cpp b/llvm/lib/Support/KnownBits.cpp
index 94a04ab90987a..a1bb6818fc94d 100644
--- a/llvm/lib/Support/KnownBits.cpp
+++ b/llvm/lib/Support/KnownBits.cpp
@@ -888,11 +888,30 @@ KnownBits KnownBits::mul(const KnownBits &LHS, const KnownBits &RHS,
Res.Zero |= (~BottomKnown).getLoBits(ResultBitsKnown);
Res.One = BottomKnown.getLoBits(ResultBitsKnown);
- // If we're self-multiplying then bit[1] is guaranteed to be zero.
- if (NoUndefSelfMultiply && BitWidth > 1) {
- assert(Res.One[1] == 0 &&
- "Self-multiplication failed Quadratic Reciprocity!");
- Res.Zero.setBit(1);
+ // Self multiplying
+ if (NoUndefSelfMultiply) {
+ // bit[1] is guaranteed to be zero.
+ if (BitWidth > 1) {
+ assert(Res.One[1] == 0 &&
+ "Self-multiplication failed Quadratic Reciprocity!");
+ Res.Zero.setBit(1);
+ }
+
+ // If input bit[0] is set, then output bit[2] is guaranteed to be zero.
+ if (BitWidth > 2 && LHS.One[0])
+ Res.Zero.setBit(2);
+
+ // If input bit[0] is clear, then output bit[3] is guaranteed to be zero.
+ if (BitWidth > 3 && LHS.Zero[0])
+ Res.Zero.setBit(3);
+
+ // If input % 4 == 2, then output bit[3] and bit[4] are guarantted to be
+ // zero.
+ if (BitWidth > 3 && LHS.Zero[0] && LHS.One[1]) {
+ Res.Zero.setBit(3);
+ if (BitWidth > 4)
+ Res.Zero.setBit(4);
+ }
}
return Res;
diff --git a/llvm/test/Transforms/InstCombine/known-bits.ll b/llvm/test/Transforms/InstCombine/known-bits.ll
index 3868b5c3701c9..f8c97d86a9230 100644
--- a/llvm/test/Transforms/InstCombine/known-bits.ll
+++ b/llvm/test/Transforms/InstCombine/known-bits.ll
@@ -1246,10 +1246,7 @@ define i1 @extract_value_smul_fail(i8 %xx, i8 %yy) {
define i8 @known_self_mul_bit_0_set(i8 noundef %x) {
; CHECK-LABEL: @known_self_mul_bit_0_set(
-; CHECK-NEXT: [[BIT_0_SET:%.*]] = or i8 [[X:%.*]], 1
-; CHECK-NEXT: [[SELF_MUL:%.*]] = mul i8 [[BIT_0_SET]], [[BIT_0_SET]]
-; CHECK-NEXT: [[R:%.*]] = and i8 [[SELF_MUL]], 4
-; CHECK-NEXT: ret i8 [[R]]
+; CHECK-NEXT: ret i8 0
;
%bit_0_set = or i8 %x, 1
%self_mul = mul i8 %bit_0_set, %bit_0_set
@@ -1259,10 +1256,7 @@ define i8 @known_self_mul_bit_0_set(i8 noundef %x) {
define i8 @known_self_mul_bit_0_unset(i8 noundef %x) {
; CHECK-LABEL: @known_self_mul_bit_0_unset(
-; CHECK-NEXT: [[BIT_0_UNSET:%.*]] = and i8 [[X:%.*]], -2
-; CHECK-NEXT: [[SELF_MUL:%.*]] = mul i8 [[BIT_0_UNSET]], [[BIT_0_UNSET]]
-; CHECK-NEXT: [[R:%.*]] = and i8 [[SELF_MUL]], 8
-; CHECK-NEXT: ret i8 [[R]]
+; CHECK-NEXT: ret i8 0
;
%bit_0_unset = and i8 %x, -2
%self_mul = mul i8 %bit_0_unset, %bit_0_unset
@@ -1272,11 +1266,7 @@ define i8 @known_self_mul_bit_0_unset(i8 noundef %x) {
define i8 @known_self_mul_bit_1_set_bit_0_unset(i8 noundef %x) {
; CHECK-LABEL: @known_self_mul_bit_1_set_bit_0_unset(
-; CHECK-NEXT: [[LOWER_2_UNSET:%.*]] = and i8 [[X:%.*]], -4
-; CHECK-NEXT: [[BIT_1_SET_BIT_0_UNSET:%.*]] = or disjoint i8 [[LOWER_2_UNSET]], 2
-; CHECK-NEXT: [[SELF_MUL:%.*]] = mul i8 [[BIT_1_SET_BIT_0_UNSET]], [[BIT_1_SET_BIT_0_UNSET]]
-; CHECK-NEXT: [[R:%.*]] = and i8 [[SELF_MUL]], 24
-; CHECK-NEXT: ret i8 [[R]]
+; CHECK-NEXT: ret i8 0
;
%lower_2_unset = and i8 %x, -4
%bit_1_set_bit_0_unset = or disjoint i8 %lower_2_unset, 2
@@ -1287,11 +1277,7 @@ define i8 @known_self_mul_bit_1_set_bit_0_unset(i8 noundef %x) {
define i4 @known_self_mul_bit_1_set_bit_0_unset_i4(i4 noundef %x) {
; CHECK-LABEL: @known_self_mul_bit_1_set_bit_0_unset_i4(
-; CHECK-NEXT: [[LOWER_2_UNSET:%.*]] = and i4 [[X:%.*]], -4
-; CHECK-NEXT: [[BIT_1_SET_BIT_0_UNSET:%.*]] = or disjoint i4 [[LOWER_2_UNSET]], 2
-; CHECK-NEXT: [[SELF_MUL:%.*]] = mul i4 [[BIT_1_SET_BIT_0_UNSET]], [[BIT_1_SET_BIT_0_UNSET]]
-; CHECK-NEXT: [[R:%.*]] = and i4 [[SELF_MUL]], -8
-; CHECK-NEXT: ret i4 [[R]]
+; CHECK-NEXT: ret i4 0
;
%lower_2_unset = and i4 %x, -4
%bit_1_set_bit_0_unset = or disjoint i4 %lower_2_unset, 2
>From 116f88acad054a1144607ace985d22fb40b03966 Mon Sep 17 00:00:00 2001
From: Macsen Casaus <macsen at fedora.localdomain>
Date: Sat, 2 Aug 2025 16:42:15 -0600
Subject: [PATCH 3/6] Generalize X * X info to all bit widths
---
llvm/lib/Support/KnownBits.cpp | 22 ++++++++++------------
1 file changed, 10 insertions(+), 12 deletions(-)
diff --git a/llvm/lib/Support/KnownBits.cpp b/llvm/lib/Support/KnownBits.cpp
index a1bb6818fc94d..377f5f13eb642 100644
--- a/llvm/lib/Support/KnownBits.cpp
+++ b/llvm/lib/Support/KnownBits.cpp
@@ -897,20 +897,18 @@ KnownBits KnownBits::mul(const KnownBits &LHS, const KnownBits &RHS,
Res.Zero.setBit(1);
}
- // If input bit[0] is set, then output bit[2] is guaranteed to be zero.
- if (BitWidth > 2 && LHS.One[0])
- Res.Zero.setBit(2);
+ // If X has TZ trailing zeroes, then bit (2 * TZ + 1) must be zero.
+ unsigned TZ = (~LHS.Zero).countr_zero();
+ unsigned TwoTZP1 = 2 * TZ + 1;
+ if (TwoTZP1 < BitWidth)
+ Res.Zero.setBit(TwoTZP1);
- // If input bit[0] is clear, then output bit[3] is guaranteed to be zero.
- if (BitWidth > 3 && LHS.Zero[0])
- Res.Zero.setBit(3);
-
- // If input % 4 == 2, then output bit[3] and bit[4] are guarantted to be
+ // If X has exactly TZ trailing zeros, then bit (2 * TZ + 2) must also be
// zero.
- if (BitWidth > 3 && LHS.Zero[0] && LHS.One[1]) {
- Res.Zero.setBit(3);
- if (BitWidth > 4)
- Res.Zero.setBit(4);
+ if (TZ < BitWidth && LHS.One[TZ]) {
+ unsigned TwoTZP2 = TwoTZP1 + 1;
+ if (TwoTZP2 < BitWidth)
+ Res.Zero.setBit(TwoTZP2);
}
}
>From fe3b0d42de636d248bc683c2fb986cbf009d96db Mon Sep 17 00:00:00 2001
From: Macsen Casaus <macsen at fedora.localdomain>
Date: Sun, 3 Aug 2025 11:41:29 -0600
Subject: [PATCH 4/6] replace TZ with TrailZero0
---
llvm/lib/Support/KnownBits.cpp | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/llvm/lib/Support/KnownBits.cpp b/llvm/lib/Support/KnownBits.cpp
index 377f5f13eb642..cd8955ade2a40 100644
--- a/llvm/lib/Support/KnownBits.cpp
+++ b/llvm/lib/Support/KnownBits.cpp
@@ -898,14 +898,13 @@ KnownBits KnownBits::mul(const KnownBits &LHS, const KnownBits &RHS,
}
// If X has TZ trailing zeroes, then bit (2 * TZ + 1) must be zero.
- unsigned TZ = (~LHS.Zero).countr_zero();
- unsigned TwoTZP1 = 2 * TZ + 1;
+ unsigned TwoTZP1 = 2 * TrailZero0 + 1;
if (TwoTZP1 < BitWidth)
Res.Zero.setBit(TwoTZP1);
// If X has exactly TZ trailing zeros, then bit (2 * TZ + 2) must also be
// zero.
- if (TZ < BitWidth && LHS.One[TZ]) {
+ if (TrailZero0 < BitWidth && LHS.One[TrailZero0]) {
unsigned TwoTZP2 = TwoTZP1 + 1;
if (TwoTZP2 < BitWidth)
Res.Zero.setBit(TwoTZP2);
>From ec4791d824a6626a68e7057a46effd309d9338ca Mon Sep 17 00:00:00 2001
From: Macsen Casaus <macsen at fedora.localdomain>
Date: Mon, 4 Aug 2025 12:10:17 -0600
Subject: [PATCH 5/6] remove redundant setBit given new generalization
---
llvm/lib/Support/KnownBits.cpp | 7 -------
1 file changed, 7 deletions(-)
diff --git a/llvm/lib/Support/KnownBits.cpp b/llvm/lib/Support/KnownBits.cpp
index cd8955ade2a40..1cdf120d9edd8 100644
--- a/llvm/lib/Support/KnownBits.cpp
+++ b/llvm/lib/Support/KnownBits.cpp
@@ -890,13 +890,6 @@ KnownBits KnownBits::mul(const KnownBits &LHS, const KnownBits &RHS,
// Self multiplying
if (NoUndefSelfMultiply) {
- // bit[1] is guaranteed to be zero.
- if (BitWidth > 1) {
- assert(Res.One[1] == 0 &&
- "Self-multiplication failed Quadratic Reciprocity!");
- Res.Zero.setBit(1);
- }
-
// If X has TZ trailing zeroes, then bit (2 * TZ + 1) must be zero.
unsigned TwoTZP1 = 2 * TrailZero0 + 1;
if (TwoTZP1 < BitWidth)
>From 8c2754ab1ab4922e9e1cc3d2afe27ac04f71dd3f Mon Sep 17 00:00:00 2001
From: Macsen Casaus <macsen at fedora.localdomain>
Date: Fri, 8 Aug 2025 18:45:34 -0600
Subject: [PATCH 6/6] reword comments
---
llvm/lib/Support/KnownBits.cpp | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/llvm/lib/Support/KnownBits.cpp b/llvm/lib/Support/KnownBits.cpp
index 1cdf120d9edd8..bd08365a3fcdb 100644
--- a/llvm/lib/Support/KnownBits.cpp
+++ b/llvm/lib/Support/KnownBits.cpp
@@ -888,9 +888,8 @@ KnownBits KnownBits::mul(const KnownBits &LHS, const KnownBits &RHS,
Res.Zero |= (~BottomKnown).getLoBits(ResultBitsKnown);
Res.One = BottomKnown.getLoBits(ResultBitsKnown);
- // Self multiplying
if (NoUndefSelfMultiply) {
- // If X has TZ trailing zeroes, then bit (2 * TZ + 1) must be zero.
+ // If X has at least TZ trailing zeroes, then bit (2 * TZ + 1) must be zero.
unsigned TwoTZP1 = 2 * TrailZero0 + 1;
if (TwoTZP1 < BitWidth)
Res.Zero.setBit(TwoTZP1);
More information about the llvm-commits
mailing list