[llvm] [ValueTracking] mul nuw nsw with factor sge 1 is non-negative (PR #110803)
Nikita Popov via llvm-commits
llvm-commits at lists.llvm.org
Wed Oct 2 01:44:36 PDT 2024
https://github.com/nikic created https://github.com/llvm/llvm-project/pull/110803
Proof: https://alive2.llvm.org/ce/z/6nRJMD
>From 4c114a795f1c1f44bcb38bee42169b532e3f3cd0 Mon Sep 17 00:00:00 2001
From: Nikita Popov <npopov at redhat.com>
Date: Wed, 2 Oct 2024 10:41:17 +0200
Subject: [PATCH 1/2] [InstCombine] Add tests for known bits of mul nuw nsw
(NFC)
---
.../test/Transforms/InstCombine/known-bits.ll | 53 +++++++++++++++++++
1 file changed, 53 insertions(+)
diff --git a/llvm/test/Transforms/InstCombine/known-bits.ll b/llvm/test/Transforms/InstCombine/known-bits.ll
index 8cfb987e422f38..abe5708224c97d 100644
--- a/llvm/test/Transforms/InstCombine/known-bits.ll
+++ b/llvm/test/Transforms/InstCombine/known-bits.ll
@@ -2051,6 +2051,59 @@ exit:
ret i16 %conv
}
+define i1 @mul_nuw_nsw_nonneg_const(i8 %x) {
+; CHECK-LABEL: @mul_nuw_nsw_nonneg_const(
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[X:%.*]], -1
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %mul = mul nuw nsw i8 %x, 3
+ %cmp = icmp sgt i8 %mul, -1
+ ret i1 %cmp
+}
+
+define i1 @mul_nuw_nsw_nonneg_can_be_one(i8 %x, i8 %y) {
+; CHECK-LABEL: @mul_nuw_nsw_nonneg_can_be_one(
+; CHECK-NEXT: [[Y_NNEG:%.*]] = and i8 [[Y:%.*]], 127
+; CHECK-NEXT: [[MUL:%.*]] = mul nuw nsw i8 [[X:%.*]], [[Y_NNEG]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[MUL]], -1
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %y.nneg = and i8 %y, 127
+ %mul = mul nuw nsw i8 %x, %y.nneg
+ %cmp = icmp sgt i8 %mul, -1
+ ret i1 %cmp
+}
+
+define i1 @mul_nuw_nsw_nonneg_cant_be_one(i8 %x, i8 %y) {
+; CHECK-LABEL: @mul_nuw_nsw_nonneg_cant_be_one(
+; CHECK-NEXT: [[Y_NNEG:%.*]] = and i8 [[Y:%.*]], 125
+; CHECK-NEXT: [[Y_NNEG_NOT_ONE:%.*]] = or disjoint i8 [[Y_NNEG]], 2
+; CHECK-NEXT: [[MUL:%.*]] = mul nuw nsw i8 [[X:%.*]], [[Y_NNEG_NOT_ONE]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[MUL]], -1
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %y.nneg = and i8 %y, 127
+ %y.nneg.not.one = or i8 %y.nneg, 2
+ %mul = mul nuw nsw i8 %x, %y.nneg.not.one
+ %cmp = icmp sgt i8 %mul, -1
+ ret i1 %cmp
+}
+
+define i1 @mul_nuw_nsw_nonneg_cant_be_one_commuted(i8 %x, i8 %y) {
+; CHECK-LABEL: @mul_nuw_nsw_nonneg_cant_be_one_commuted(
+; CHECK-NEXT: [[Y_NNEG:%.*]] = and i8 [[Y:%.*]], 125
+; CHECK-NEXT: [[Y_NNEG_NOT_ONE:%.*]] = or disjoint i8 [[Y_NNEG]], 2
+; CHECK-NEXT: [[MUL:%.*]] = mul nuw nsw i8 [[Y_NNEG_NOT_ONE]], [[X:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[MUL]], -1
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %y.nneg = and i8 %y, 127
+ %y.nneg.not.one = or i8 %y.nneg, 2
+ %mul = mul nuw nsw i8 %y.nneg.not.one, %x
+ %cmp = icmp sgt i8 %mul, -1
+ ret i1 %cmp
+}
+
declare void @dummy()
declare void @use(i1)
declare void @sink(i8)
>From 5206bf9408088a7915c6dad4539d2cd549a4ab37 Mon Sep 17 00:00:00 2001
From: Nikita Popov <npopov at redhat.com>
Date: Wed, 2 Oct 2024 10:31:57 +0200
Subject: [PATCH 2/2] [ValueTracking] mul nuw nsw with >1 is nneg
---
llvm/lib/Analysis/ValueTracking.cpp | 20 +++++++++++++------
llvm/test/Transforms/InstCombine/ashr-lshr.ll | 4 ++--
.../test/Transforms/InstCombine/known-bits.ll | 15 +++-----------
.../Transforms/InstCombine/rem-mul-shl.ll | 2 +-
4 files changed, 20 insertions(+), 21 deletions(-)
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 56eb3f99b39d2c..0d384c61f978ee 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -369,9 +369,9 @@ static void computeKnownBitsAddSub(bool Add, const Value *Op0, const Value *Op1,
}
static void computeKnownBitsMul(const Value *Op0, const Value *Op1, bool NSW,
- const APInt &DemandedElts, KnownBits &Known,
- KnownBits &Known2, unsigned Depth,
- const SimplifyQuery &Q) {
+ bool NUW, const APInt &DemandedElts,
+ KnownBits &Known, KnownBits &Known2,
+ unsigned Depth, const SimplifyQuery &Q) {
computeKnownBits(Op1, DemandedElts, Known, Depth + 1, Q);
computeKnownBits(Op0, DemandedElts, Known2, Depth + 1, Q);
@@ -390,6 +390,13 @@ static void computeKnownBitsMul(const Value *Op0, const Value *Op1, bool NSW,
// The product of two numbers with the same sign is non-negative.
isKnownNonNegative = (isKnownNegativeOp1 && isKnownNegativeOp0) ||
(isKnownNonNegativeOp1 && isKnownNonNegativeOp0);
+ if (!isKnownNonNegative && NUW) {
+ // mul nuw nsw with a factor > 1 is non-negative.
+ KnownBits One = KnownBits::makeConstant(APInt(Known.getBitWidth(), 1));
+ isKnownNonNegative = KnownBits::sgt(Known, One).value_or(false) ||
+ KnownBits::sgt(Known2, One).value_or(false);
+ }
+
// The product of a negative number and a non-negative number is either
// negative or zero.
if (!isKnownNonNegative)
@@ -1090,8 +1097,9 @@ static void computeKnownBitsFromOperator(const Operator *I,
break;
case Instruction::Mul: {
bool NSW = Q.IIQ.hasNoSignedWrap(cast<OverflowingBinaryOperator>(I));
- computeKnownBitsMul(I->getOperand(0), I->getOperand(1), NSW, DemandedElts,
- Known, Known2, Depth, Q);
+ bool NUW = Q.IIQ.hasNoUnsignedWrap(cast<OverflowingBinaryOperator>(I));
+ computeKnownBitsMul(I->getOperand(0), I->getOperand(1), NSW, NUW,
+ DemandedElts, Known, Known2, Depth, Q);
break;
}
case Instruction::UDiv: {
@@ -1961,7 +1969,7 @@ static void computeKnownBitsFromOperator(const Operator *I,
case Intrinsic::umul_with_overflow:
case Intrinsic::smul_with_overflow:
computeKnownBitsMul(II->getArgOperand(0), II->getArgOperand(1), false,
- DemandedElts, Known, Known2, Depth, Q);
+ false, DemandedElts, Known, Known2, Depth, Q);
break;
}
}
diff --git a/llvm/test/Transforms/InstCombine/ashr-lshr.ll b/llvm/test/Transforms/InstCombine/ashr-lshr.ll
index 49041906680b3a..1abf1be2cbedd9 100644
--- a/llvm/test/Transforms/InstCombine/ashr-lshr.ll
+++ b/llvm/test/Transforms/InstCombine/ashr-lshr.ll
@@ -741,7 +741,7 @@ define i32 @lshr_mul_times_5_div_4_exact_2(i32 %x) {
define i32 @ashr_mul_times_3_div_2(i32 %0) {
; CHECK-LABEL: @ashr_mul_times_3_div_2(
-; CHECK-NEXT: [[TMP2:%.*]] = ashr i32 [[TMP0:%.*]], 1
+; CHECK-NEXT: [[TMP2:%.*]] = lshr i32 [[TMP0:%.*]], 1
; CHECK-NEXT: [[ASHR:%.*]] = add nuw nsw i32 [[TMP0]], [[TMP2]]
; CHECK-NEXT: ret i32 [[ASHR]]
;
@@ -815,7 +815,7 @@ define i32 @ashr_mul_times_3_div_2_exact_2(i32 %x) {
define i32 @ashr_mul_times_5_div_4(i32 %0) {
; CHECK-LABEL: @ashr_mul_times_5_div_4(
-; CHECK-NEXT: [[TMP2:%.*]] = ashr i32 [[TMP0:%.*]], 2
+; CHECK-NEXT: [[TMP2:%.*]] = lshr i32 [[TMP0:%.*]], 2
; CHECK-NEXT: [[ASHR:%.*]] = add nuw nsw i32 [[TMP0]], [[TMP2]]
; CHECK-NEXT: ret i32 [[ASHR]]
;
diff --git a/llvm/test/Transforms/InstCombine/known-bits.ll b/llvm/test/Transforms/InstCombine/known-bits.ll
index abe5708224c97d..d5393492c31ff1 100644
--- a/llvm/test/Transforms/InstCombine/known-bits.ll
+++ b/llvm/test/Transforms/InstCombine/known-bits.ll
@@ -2053,8 +2053,7 @@ exit:
define i1 @mul_nuw_nsw_nonneg_const(i8 %x) {
; CHECK-LABEL: @mul_nuw_nsw_nonneg_const(
-; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[X:%.*]], -1
-; CHECK-NEXT: ret i1 [[CMP]]
+; CHECK-NEXT: ret i1 true
;
%mul = mul nuw nsw i8 %x, 3
%cmp = icmp sgt i8 %mul, -1
@@ -2076,11 +2075,7 @@ define i1 @mul_nuw_nsw_nonneg_can_be_one(i8 %x, i8 %y) {
define i1 @mul_nuw_nsw_nonneg_cant_be_one(i8 %x, i8 %y) {
; CHECK-LABEL: @mul_nuw_nsw_nonneg_cant_be_one(
-; CHECK-NEXT: [[Y_NNEG:%.*]] = and i8 [[Y:%.*]], 125
-; CHECK-NEXT: [[Y_NNEG_NOT_ONE:%.*]] = or disjoint i8 [[Y_NNEG]], 2
-; CHECK-NEXT: [[MUL:%.*]] = mul nuw nsw i8 [[X:%.*]], [[Y_NNEG_NOT_ONE]]
-; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[MUL]], -1
-; CHECK-NEXT: ret i1 [[CMP]]
+; CHECK-NEXT: ret i1 true
;
%y.nneg = and i8 %y, 127
%y.nneg.not.one = or i8 %y.nneg, 2
@@ -2091,11 +2086,7 @@ define i1 @mul_nuw_nsw_nonneg_cant_be_one(i8 %x, i8 %y) {
define i1 @mul_nuw_nsw_nonneg_cant_be_one_commuted(i8 %x, i8 %y) {
; CHECK-LABEL: @mul_nuw_nsw_nonneg_cant_be_one_commuted(
-; CHECK-NEXT: [[Y_NNEG:%.*]] = and i8 [[Y:%.*]], 125
-; CHECK-NEXT: [[Y_NNEG_NOT_ONE:%.*]] = or disjoint i8 [[Y_NNEG]], 2
-; CHECK-NEXT: [[MUL:%.*]] = mul nuw nsw i8 [[Y_NNEG_NOT_ONE]], [[X:%.*]]
-; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[MUL]], -1
-; CHECK-NEXT: ret i1 [[CMP]]
+; CHECK-NEXT: ret i1 true
;
%y.nneg = and i8 %y, 127
%y.nneg.not.one = or i8 %y.nneg, 2
diff --git a/llvm/test/Transforms/InstCombine/rem-mul-shl.ll b/llvm/test/Transforms/InstCombine/rem-mul-shl.ll
index 9e2df157c2c858..45db2cf6758524 100644
--- a/llvm/test/Transforms/InstCombine/rem-mul-shl.ll
+++ b/llvm/test/Transforms/InstCombine/rem-mul-shl.ll
@@ -8,7 +8,7 @@ define i8 @srem_non_matching(i8 %X, i8 %Y) {
; CHECK-LABEL: @srem_non_matching(
; CHECK-NEXT: [[BO0:%.*]] = mul nuw nsw i8 [[X:%.*]], 15
; CHECK-NEXT: [[BO1:%.*]] = mul nuw nsw i8 [[Y:%.*]], 5
-; CHECK-NEXT: [[R:%.*]] = srem i8 [[BO0]], [[BO1]]
+; CHECK-NEXT: [[R:%.*]] = urem i8 [[BO0]], [[BO1]]
; CHECK-NEXT: ret i8 [[R]]
;
%BO0 = mul nsw nuw i8 %X, 15
More information about the llvm-commits
mailing list