Skip to content

Commit eb85285

Browse files
authored
[ValueTracking] mul nuw nsw with factor sgt 1 is non-negative (#110803)
Proof: https://alive2.llvm.org/ce/z/bC0eJf
1 parent 5f909c0 commit eb85285

File tree

4 files changed

+82
-9
lines changed

4 files changed

+82
-9
lines changed

llvm/lib/Analysis/ValueTracking.cpp

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -369,9 +369,9 @@ static void computeKnownBitsAddSub(bool Add, const Value *Op0, const Value *Op1,
369369
}
370370

371371
static void computeKnownBitsMul(const Value *Op0, const Value *Op1, bool NSW,
372-
const APInt &DemandedElts, KnownBits &Known,
373-
KnownBits &Known2, unsigned Depth,
374-
const SimplifyQuery &Q) {
372+
bool NUW, const APInt &DemandedElts,
373+
KnownBits &Known, KnownBits &Known2,
374+
unsigned Depth, const SimplifyQuery &Q) {
375375
computeKnownBits(Op1, DemandedElts, Known, Depth + 1, Q);
376376
computeKnownBits(Op0, DemandedElts, Known2, Depth + 1, Q);
377377

@@ -390,6 +390,13 @@ static void computeKnownBitsMul(const Value *Op0, const Value *Op1, bool NSW,
390390
// The product of two numbers with the same sign is non-negative.
391391
isKnownNonNegative = (isKnownNegativeOp1 && isKnownNegativeOp0) ||
392392
(isKnownNonNegativeOp1 && isKnownNonNegativeOp0);
393+
if (!isKnownNonNegative && NUW) {
394+
// mul nuw nsw with a factor > 1 is non-negative.
395+
KnownBits One = KnownBits::makeConstant(APInt(Known.getBitWidth(), 1));
396+
isKnownNonNegative = KnownBits::sgt(Known, One).value_or(false) ||
397+
KnownBits::sgt(Known2, One).value_or(false);
398+
}
399+
393400
// The product of a negative number and a non-negative number is either
394401
// negative or zero.
395402
if (!isKnownNonNegative)
@@ -1090,8 +1097,9 @@ static void computeKnownBitsFromOperator(const Operator *I,
10901097
break;
10911098
case Instruction::Mul: {
10921099
bool NSW = Q.IIQ.hasNoSignedWrap(cast<OverflowingBinaryOperator>(I));
1093-
computeKnownBitsMul(I->getOperand(0), I->getOperand(1), NSW, DemandedElts,
1094-
Known, Known2, Depth, Q);
1100+
bool NUW = Q.IIQ.hasNoUnsignedWrap(cast<OverflowingBinaryOperator>(I));
1101+
computeKnownBitsMul(I->getOperand(0), I->getOperand(1), NSW, NUW,
1102+
DemandedElts, Known, Known2, Depth, Q);
10951103
break;
10961104
}
10971105
case Instruction::UDiv: {
@@ -1959,7 +1967,7 @@ static void computeKnownBitsFromOperator(const Operator *I,
19591967
case Intrinsic::umul_with_overflow:
19601968
case Intrinsic::smul_with_overflow:
19611969
computeKnownBitsMul(II->getArgOperand(0), II->getArgOperand(1), false,
1962-
DemandedElts, Known, Known2, Depth, Q);
1970+
false, DemandedElts, Known, Known2, Depth, Q);
19631971
break;
19641972
}
19651973
}

llvm/test/Transforms/InstCombine/ashr-lshr.ll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -741,7 +741,7 @@ define i32 @lshr_mul_times_5_div_4_exact_2(i32 %x) {
741741

742742
define i32 @ashr_mul_times_3_div_2(i32 %0) {
743743
; CHECK-LABEL: @ashr_mul_times_3_div_2(
744-
; CHECK-NEXT: [[TMP2:%.*]] = ashr i32 [[TMP0:%.*]], 1
744+
; CHECK-NEXT: [[TMP2:%.*]] = lshr i32 [[TMP0:%.*]], 1
745745
; CHECK-NEXT: [[ASHR:%.*]] = add nuw nsw i32 [[TMP0]], [[TMP2]]
746746
; CHECK-NEXT: ret i32 [[ASHR]]
747747
;
@@ -815,7 +815,7 @@ define i32 @ashr_mul_times_3_div_2_exact_2(i32 %x) {
815815

816816
define i32 @ashr_mul_times_5_div_4(i32 %0) {
817817
; CHECK-LABEL: @ashr_mul_times_5_div_4(
818-
; CHECK-NEXT: [[TMP2:%.*]] = ashr i32 [[TMP0:%.*]], 2
818+
; CHECK-NEXT: [[TMP2:%.*]] = lshr i32 [[TMP0:%.*]], 2
819819
; CHECK-NEXT: [[ASHR:%.*]] = add nuw nsw i32 [[TMP0]], [[TMP2]]
820820
; CHECK-NEXT: ret i32 [[ASHR]]
821821
;

llvm/test/Transforms/InstCombine/known-bits.ll

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2051,6 +2051,71 @@ exit:
20512051
ret i16 %conv
20522052
}
20532053

2054+
define i1 @mul_nuw_nsw_nonneg_const(i8 %x) {
2055+
; CHECK-LABEL: @mul_nuw_nsw_nonneg_const(
2056+
; CHECK-NEXT: ret i1 true
2057+
;
2058+
%mul = mul nuw nsw i8 %x, 3
2059+
%cmp = icmp sgt i8 %mul, -1
2060+
ret i1 %cmp
2061+
}
2062+
2063+
define i1 @mul_nuw_nsw_nonneg_const_missing_nuw(i8 %x) {
2064+
; CHECK-LABEL: @mul_nuw_nsw_nonneg_const_missing_nuw(
2065+
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[X:%.*]], -1
2066+
; CHECK-NEXT: ret i1 [[CMP]]
2067+
;
2068+
%mul = mul nsw i8 %x, 3
2069+
%cmp = icmp sgt i8 %mul, -1
2070+
ret i1 %cmp
2071+
}
2072+
2073+
define i1 @mul_nuw_nsw_nonneg_const_missing_nsw(i8 %x) {
2074+
; CHECK-LABEL: @mul_nuw_nsw_nonneg_const_missing_nsw(
2075+
; CHECK-NEXT: [[MUL:%.*]] = mul nuw i8 [[X:%.*]], 3
2076+
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[MUL]], -1
2077+
; CHECK-NEXT: ret i1 [[CMP]]
2078+
;
2079+
%mul = mul nuw i8 %x, 3
2080+
%cmp = icmp sgt i8 %mul, -1
2081+
ret i1 %cmp
2082+
}
2083+
2084+
define i1 @mul_nuw_nsw_nonneg_can_be_one(i8 %x, i8 %y) {
2085+
; CHECK-LABEL: @mul_nuw_nsw_nonneg_can_be_one(
2086+
; CHECK-NEXT: [[Y_NNEG:%.*]] = and i8 [[Y:%.*]], 127
2087+
; CHECK-NEXT: [[MUL:%.*]] = mul nuw nsw i8 [[X:%.*]], [[Y_NNEG]]
2088+
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[MUL]], -1
2089+
; CHECK-NEXT: ret i1 [[CMP]]
2090+
;
2091+
%y.nneg = and i8 %y, 127
2092+
%mul = mul nuw nsw i8 %x, %y.nneg
2093+
%cmp = icmp sgt i8 %mul, -1
2094+
ret i1 %cmp
2095+
}
2096+
2097+
define i1 @mul_nuw_nsw_nonneg_cant_be_one(i8 %x, i8 %y) {
2098+
; CHECK-LABEL: @mul_nuw_nsw_nonneg_cant_be_one(
2099+
; CHECK-NEXT: ret i1 true
2100+
;
2101+
%y.nneg = and i8 %y, 127
2102+
%y.nneg.not.one = or i8 %y.nneg, 2
2103+
%mul = mul nuw nsw i8 %x, %y.nneg.not.one
2104+
%cmp = icmp sgt i8 %mul, -1
2105+
ret i1 %cmp
2106+
}
2107+
2108+
define i1 @mul_nuw_nsw_nonneg_cant_be_one_commuted(i8 %x, i8 %y) {
2109+
; CHECK-LABEL: @mul_nuw_nsw_nonneg_cant_be_one_commuted(
2110+
; CHECK-NEXT: ret i1 true
2111+
;
2112+
%y.nneg = and i8 %y, 127
2113+
%y.nneg.not.one = or i8 %y.nneg, 2
2114+
%mul = mul nuw nsw i8 %y.nneg.not.one, %x
2115+
%cmp = icmp sgt i8 %mul, -1
2116+
ret i1 %cmp
2117+
}
2118+
20542119
declare void @dummy()
20552120
declare void @use(i1)
20562121
declare void @sink(i8)

llvm/test/Transforms/InstCombine/rem-mul-shl.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ define i8 @srem_non_matching(i8 %X, i8 %Y) {
88
; CHECK-LABEL: @srem_non_matching(
99
; CHECK-NEXT: [[BO0:%.*]] = mul nuw nsw i8 [[X:%.*]], 15
1010
; CHECK-NEXT: [[BO1:%.*]] = mul nuw nsw i8 [[Y:%.*]], 5
11-
; CHECK-NEXT: [[R:%.*]] = srem i8 [[BO0]], [[BO1]]
11+
; CHECK-NEXT: [[R:%.*]] = urem i8 [[BO0]], [[BO1]]
1212
; CHECK-NEXT: ret i8 [[R]]
1313
;
1414
%BO0 = mul nsw nuw i8 %X, 15

0 commit comments

Comments
 (0)