diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp index e61480d7542d7..57c7dcd69b21d 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -692,12 +692,24 @@ static Instruction *foldCtpop(IntrinsicInst &II, InstCombinerImpl &IC) { Ty); // Add range attribute since known bits can't completely reflect what we know. - if (BitWidth != 1 && !II.hasRetAttr(Attribute::Range) && - !II.getMetadata(LLVMContext::MD_range)) { - ConstantRange Range(APInt(BitWidth, Known.countMinPopulation()), - APInt(BitWidth, Known.countMaxPopulation() + 1)); - II.addRangeRetAttr(Range); - return &II; + if (BitWidth != 1) { + ConstantRange OldRange = + II.getRange().value_or(ConstantRange::getFull(BitWidth)); + + unsigned Lower = Known.countMinPopulation(); + unsigned Upper = Known.countMaxPopulation() + 1; + + if (Lower == 0 && OldRange.contains(APInt::getZero(BitWidth)) && + isKnownNonZero(Op0, IC.getSimplifyQuery().getWithInstruction(&II))) + Lower = 1; + + ConstantRange Range(APInt(BitWidth, Lower), APInt(BitWidth, Upper)); + Range = Range.intersectWith(OldRange, ConstantRange::Unsigned); + + if (Range != OldRange) { + II.addRangeRetAttr(Range); + return &II; + } } return nullptr; diff --git a/llvm/test/Transforms/InstCombine/ctpop-pow2.ll b/llvm/test/Transforms/InstCombine/ctpop-pow2.ll index 7facdaf7590d3..4ef1ed0ec4976 100644 --- a/llvm/test/Transforms/InstCombine/ctpop-pow2.ll +++ b/llvm/test/Transforms/InstCombine/ctpop-pow2.ll @@ -60,7 +60,7 @@ define i8 @ctpop_imin_plus1_lshr_nz(i8 %x) { ; CHECK-NEXT: [[CMP:%.*]] = icmp ne i8 [[X:%.*]], 0 ; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]]) ; CHECK-NEXT: [[V:%.*]] = lshr i8 -127, [[X]] -; CHECK-NEXT: [[CNT:%.*]] = call range(i8 0, 9) i8 @llvm.ctpop.i8(i8 [[V]]) +; CHECK-NEXT: [[CNT:%.*]] = call range(i8 1, 9) i8 @llvm.ctpop.i8(i8 [[V]]) ; CHECK-NEXT: ret i8 [[CNT]] ; %cmp = icmp ne i8 %x, 0 @@ -104,7 +104,7 @@ define <2 x i32> @ctpop_lshr_intmin_intmin_plus1_vec_nz(<2 x i32> %x) { ; CHECK-LABEL: @ctpop_lshr_intmin_intmin_plus1_vec_nz( ; CHECK-NEXT: [[X1:%.*]] = or <2 x i32> [[X:%.*]], ; CHECK-NEXT: [[SHR:%.*]] = lshr <2 x i32> , [[X1]] -; CHECK-NEXT: [[CNT:%.*]] = call range(i32 0, 17) <2 x i32> @llvm.ctpop.v2i32(<2 x i32> [[SHR]]) +; CHECK-NEXT: [[CNT:%.*]] = call range(i32 1, 17) <2 x i32> @llvm.ctpop.v2i32(<2 x i32> [[SHR]]) ; CHECK-NEXT: ret <2 x i32> [[CNT]] ; %x1 = or <2 x i32> %x, diff --git a/llvm/test/Transforms/InstCombine/ctpop.ll b/llvm/test/Transforms/InstCombine/ctpop.ll index 83700e72de080..940bb868c4c61 100644 --- a/llvm/test/Transforms/InstCombine/ctpop.ll +++ b/llvm/test/Transforms/InstCombine/ctpop.ll @@ -169,8 +169,8 @@ define <2 x i32> @_parity_of_not_poison(<2 x i32> %x) { define <2 x i32> @_parity_of_not_poison2(<2 x i32> %x) { ; CHECK-LABEL: @_parity_of_not_poison2( -; CHECK-NEXT: [[CNT:%.*]] = call range(i32 0, 33) <2 x i32> @llvm.ctpop.v2i32(<2 x i32> [[X:%.*]]) -; CHECK-NEXT: [[R:%.*]] = and <2 x i32> [[CNT]], +; CHECK-NEXT: [[TMP1:%.*]] = call range(i32 0, 33) <2 x i32> @llvm.ctpop.v2i32(<2 x i32> [[X:%.*]]) +; CHECK-NEXT: [[R:%.*]] = and <2 x i32> [[TMP1]], ; CHECK-NEXT: ret <2 x i32> [[R]] ; %neg = xor <2 x i32> %x, @@ -485,3 +485,21 @@ define i32 @select_ctpop_zero(i32 %x) { %res = select i1 %cmp, i32 0, i32 %ctpop ret i32 %res } + +define i32 @ctpop_non_zero(i32 range(i32 1, 255) %x) { +; CHECK-LABEL: @ctpop_non_zero( +; CHECK-NEXT: [[CTPOP:%.*]] = call range(i32 1, 9) i32 @llvm.ctpop.i32(i32 [[X:%.*]]) +; CHECK-NEXT: ret i32 [[CTPOP]] +; + %ctpop = call i32 @llvm.ctpop.i32(i32 %x) + ret i32 %ctpop +} + +define i32 @ctpop_non_zero_with_existing_range_attr(i32 range(i32 1, 255) %x) { +; CHECK-LABEL: @ctpop_non_zero_with_existing_range_attr( +; CHECK-NEXT: [[CTPOP:%.*]] = call range(i32 1, 9) i32 @llvm.ctpop.i32(i32 [[X:%.*]]) +; CHECK-NEXT: ret i32 [[CTPOP]] +; + %ctpop = call range(i32 0, 9) i32 @llvm.ctpop.i32(i32 %x) + ret i32 %ctpop +} diff --git a/llvm/test/Transforms/InstCombine/icmp-ne-pow2.ll b/llvm/test/Transforms/InstCombine/icmp-ne-pow2.ll index e9ec6b415d462..618f5d641dc1a 100644 --- a/llvm/test/Transforms/InstCombine/icmp-ne-pow2.ll +++ b/llvm/test/Transforms/InstCombine/icmp-ne-pow2.ll @@ -306,7 +306,7 @@ define i32 @pow2_32_nonconst_assume(i32 %x, i32 %y) { define i32 @pow2_32_gtnonconst_assume(i32 %x, i32 %y) { ; CHECK-LABEL: @pow2_32_gtnonconst_assume( -; CHECK-NEXT: [[CTPOP:%.*]] = call range(i32 0, 33) i32 @llvm.ctpop.i32(i32 [[Y:%.*]]) +; CHECK-NEXT: [[CTPOP:%.*]] = call range(i32 1, 33) i32 @llvm.ctpop.i32(i32 [[Y:%.*]]) ; CHECK-NEXT: [[YP2:%.*]] = icmp eq i32 [[CTPOP]], 1 ; CHECK-NEXT: call void @llvm.assume(i1 [[YP2]]) ; CHECK-NEXT: [[YGT:%.*]] = icmp ugt i32 [[Y]], [[X:%.*]] @@ -513,7 +513,7 @@ define i32 @maybe_pow2_32_noncont(i32 %x, i32 %y) { ; CHECK-NEXT: [[YGT8:%.*]] = icmp ugt i32 [[Y:%.*]], 8 ; CHECK-NEXT: br i1 [[YGT8]], label [[CONT1:%.*]], label [[CONT2:%.*]] ; CHECK: Cont1: -; CHECK-NEXT: [[CTPOP:%.*]] = call range(i32 0, 33) i32 @llvm.ctpop.i32(i32 [[Y]]) +; CHECK-NEXT: [[CTPOP:%.*]] = call range(i32 1, 33) i32 @llvm.ctpop.i32(i32 [[Y]]) ; CHECK-NEXT: [[YP2:%.*]] = icmp eq i32 [[CTPOP]], 1 ; CHECK-NEXT: call void @llvm.assume(i1 [[YP2]]) ; CHECK-NEXT: br i1 true, label [[CONT2]], label [[FALSE:%.*]] diff --git a/llvm/test/Transforms/InstCombine/ispow2.ll b/llvm/test/Transforms/InstCombine/ispow2.ll index a143b1347ccee..3f2c31d05f3ed 100644 --- a/llvm/test/Transforms/InstCombine/ispow2.ll +++ b/llvm/test/Transforms/InstCombine/ispow2.ll @@ -197,7 +197,7 @@ define i1 @is_pow2_non_zero_ult_2(i32 %x) { ; CHECK-LABEL: @is_pow2_non_zero_ult_2( ; CHECK-NEXT: [[NOTZERO:%.*]] = icmp ne i32 [[X:%.*]], 0 ; CHECK-NEXT: call void @llvm.assume(i1 [[NOTZERO]]) -; CHECK-NEXT: [[T0:%.*]] = tail call range(i32 0, 33) i32 @llvm.ctpop.i32(i32 [[X]]) +; CHECK-NEXT: [[T0:%.*]] = tail call range(i32 1, 33) i32 @llvm.ctpop.i32(i32 [[X]]) ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[T0]], 2 ; CHECK-NEXT: ret i1 [[CMP]] ; @@ -212,7 +212,7 @@ define i1 @is_pow2_non_zero_eq_1(i32 %x) { ; CHECK-LABEL: @is_pow2_non_zero_eq_1( ; CHECK-NEXT: [[NOTZERO:%.*]] = icmp ne i32 [[X:%.*]], 0 ; CHECK-NEXT: call void @llvm.assume(i1 [[NOTZERO]]) -; CHECK-NEXT: [[T0:%.*]] = tail call range(i32 0, 33) i32 @llvm.ctpop.i32(i32 [[X]]) +; CHECK-NEXT: [[T0:%.*]] = tail call range(i32 1, 33) i32 @llvm.ctpop.i32(i32 [[X]]) ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[T0]], 1 ; CHECK-NEXT: ret i1 [[CMP]] ; @@ -227,7 +227,7 @@ define i1 @is_pow2_non_zero_ugt_1(i32 %x) { ; CHECK-LABEL: @is_pow2_non_zero_ugt_1( ; CHECK-NEXT: [[NOTZERO:%.*]] = icmp ne i32 [[X:%.*]], 0 ; CHECK-NEXT: call void @llvm.assume(i1 [[NOTZERO]]) -; CHECK-NEXT: [[T0:%.*]] = tail call range(i32 0, 33) i32 @llvm.ctpop.i32(i32 [[X]]) +; CHECK-NEXT: [[T0:%.*]] = tail call range(i32 1, 33) i32 @llvm.ctpop.i32(i32 [[X]]) ; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i32 [[T0]], 1 ; CHECK-NEXT: ret i1 [[CMP]] ; @@ -242,7 +242,7 @@ define i1 @is_pow2_non_zero_ne_1(i32 %x) { ; CHECK-LABEL: @is_pow2_non_zero_ne_1( ; CHECK-NEXT: [[NOTZERO:%.*]] = icmp ne i32 [[X:%.*]], 0 ; CHECK-NEXT: call void @llvm.assume(i1 [[NOTZERO]]) -; CHECK-NEXT: [[T0:%.*]] = tail call range(i32 0, 33) i32 @llvm.ctpop.i32(i32 [[X]]) +; CHECK-NEXT: [[T0:%.*]] = tail call range(i32 1, 33) i32 @llvm.ctpop.i32(i32 [[X]]) ; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[T0]], 1 ; CHECK-NEXT: ret i1 [[CMP]] ;