[llvm] ef1539c - [InstCombine] Fold out-of-range bits for squaring signed integers (#153484)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Sep 5 07:49:00 PDT 2025
Author: Aethezz
Date: 2025-09-05T16:48:57+02:00
New Revision: ef1539c1d4e205b05bd8662c9d4e90382d2381a5
URL: https://github.com/llvm/llvm-project/commit/ef1539c1d4e205b05bd8662c9d4e90382d2381a5
DIFF: https://github.com/llvm/llvm-project/commit/ef1539c1d4e205b05bd8662c9d4e90382d2381a5.diff
LOG: [InstCombine] Fold out-of-range bits for squaring signed integers (#153484)
Fixes an issue where bits next to the sign bit were not constant-folded
when squaring a sign- or zero-extended small integer. Added logic to
detect when both operands of a multiplication are the same extended
value, allowing InstCombine to mark bits above the maximum possible
square as known zero. This enables correct folding of (x * x) & (1 << N)
to 0 when N is out of range.
Proof: https://alive2.llvm.org/ce/z/YGou44
Fixes #152061
Added:
Modified:
llvm/lib/Analysis/ValueTracking.cpp
llvm/test/Transforms/InstCombine/sext.ll
Removed:
################################################################################
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 07950f5341d6c..129823e0e98a3 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -413,6 +413,18 @@ static void computeKnownBitsMul(const Value *Op0, const Value *Op1, bool NSW,
isGuaranteedNotToBeUndef(Op0, Q.AC, Q.CxtI, Q.DT, Depth + 1);
Known = KnownBits::mul(Known, Known2, SelfMultiply);
+ if (SelfMultiply) {
+ unsigned SignBits = ComputeNumSignBits(Op0, DemandedElts, Q, Depth + 1);
+ unsigned TyBits = Op0->getType()->getScalarSizeInBits();
+ unsigned OutValidBits = 2 * (TyBits - SignBits + 1);
+
+ if (OutValidBits < TyBits) {
+ APInt KnownZeroMask =
+ APInt::getHighBitsSet(TyBits, TyBits - OutValidBits + 1);
+ Known.Zero |= KnownZeroMask;
+ }
+ }
+
// Only make use of no-wrap flags if we failed to compute the sign bit
// directly. This matters if the multiplication always overflows, in
// which case we prefer to follow the result of the direct computation,
diff --git a/llvm/test/Transforms/InstCombine/sext.ll b/llvm/test/Transforms/InstCombine/sext.ll
index ee3c52259f930..c72614d526036 100644
--- a/llvm/test/Transforms/InstCombine/sext.ll
+++ b/llvm/test/Transforms/InstCombine/sext.ll
@@ -423,3 +423,41 @@ define i64 @smear_set_bit_
diff erent_dest_type_wider_dst(i32 %x) {
%s = sext i8 %a to i64
ret i64 %s
}
+
+; Test known bits for (sext i8 x) * (sext i8 x)
+
+define i1 @sext_square_bit30(i8 noundef %x) {
+; CHECK-LABEL: @sext_square_bit30(
+; CHECK-NEXT: ret i1 false
+;
+ %sx = sext i8 %x to i32
+ %mul = mul nsw i32 %sx, %sx
+ %and = and i32 %mul, 1073741824 ; 1 << 30
+ %cmp = icmp ne i32 %and, 0
+ ret i1 %cmp
+}
+
+define i1 @sext_square_bit15(i8 noundef %x) {
+; CHECK-LABEL: @sext_square_bit15(
+; CHECK-NEXT: ret i1 false
+;
+ %sx = sext i8 %x to i32
+ %mul = mul nsw i32 %sx, %sx
+ %and = and i32 %mul, 32768 ; 1 << 15
+ %cmp = icmp ne i32 %and, 0
+ ret i1 %cmp
+}
+
+define i1 @sext_square_bit14(i8 noundef %x) {
+; CHECK-LABEL: @sext_square_bit14(
+; CHECK-NEXT: [[SX:%.*]] = sext i8 [[X:%.*]] to i32
+; CHECK-NEXT: [[MUL:%.*]] = mul nsw i32 [[SX]], [[SX]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp samesign ugt i32 [[MUL]], 16383
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %sx = sext i8 %x to i32
+ %mul = mul nsw i32 %sx, %sx
+ %and = and i32 %mul, 16384 ; 1 << 14
+ %cmp = icmp ne i32 %and, 0
+ ret i1 %cmp
+}
More information about the llvm-commits
mailing list