From 4d0e99052769aeb8f5eb92745dad2733364b0664 Mon Sep 17 00:00:00 2001 From: Macsen Casaus Date: Tue, 29 Jul 2025 10:44:11 -0600 Subject: [PATCH 1/5] 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 Date: Tue, 29 Jul 2025 10:45:28 -0600 Subject: [PATCH 2/5] 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 Date: Sat, 2 Aug 2025 16:42:15 -0600 Subject: [PATCH 3/5] 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 Date: Sun, 3 Aug 2025 11:41:29 -0600 Subject: [PATCH 4/5] 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 Date: Mon, 4 Aug 2025 12:10:17 -0600 Subject: [PATCH 5/5] 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)