diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp index 56eb3f99b39d2..0d384c61f978e 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(I)); - computeKnownBitsMul(I->getOperand(0), I->getOperand(1), NSW, DemandedElts, - Known, Known2, Depth, Q); + bool NUW = Q.IIQ.hasNoUnsignedWrap(cast(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 49041906680b3..1abf1be2cbedd 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 8cfb987e422f3..aa24ec3905f13 100644 --- a/llvm/test/Transforms/InstCombine/known-bits.ll +++ b/llvm/test/Transforms/InstCombine/known-bits.ll @@ -2051,6 +2051,71 @@ exit: ret i16 %conv } +define i1 @mul_nuw_nsw_nonneg_const(i8 %x) { +; CHECK-LABEL: @mul_nuw_nsw_nonneg_const( +; CHECK-NEXT: ret i1 true +; + %mul = mul nuw nsw i8 %x, 3 + %cmp = icmp sgt i8 %mul, -1 + ret i1 %cmp +} + +define i1 @mul_nuw_nsw_nonneg_const_missing_nuw(i8 %x) { +; CHECK-LABEL: @mul_nuw_nsw_nonneg_const_missing_nuw( +; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[X:%.*]], -1 +; CHECK-NEXT: ret i1 [[CMP]] +; + %mul = mul nsw i8 %x, 3 + %cmp = icmp sgt i8 %mul, -1 + ret i1 %cmp +} + +define i1 @mul_nuw_nsw_nonneg_const_missing_nsw(i8 %x) { +; CHECK-LABEL: @mul_nuw_nsw_nonneg_const_missing_nsw( +; CHECK-NEXT: [[MUL:%.*]] = mul nuw i8 [[X:%.*]], 3 +; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[MUL]], -1 +; CHECK-NEXT: ret i1 [[CMP]] +; + %mul = mul nuw 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: ret i1 true +; + %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: ret i1 true +; + %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) diff --git a/llvm/test/Transforms/InstCombine/rem-mul-shl.ll b/llvm/test/Transforms/InstCombine/rem-mul-shl.ll index 9e2df157c2c85..45db2cf675852 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