diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -621,6 +621,11 @@ Value *Op0 = II.getArgOperand(0); Value *X, *Y; + // ctpop(X) -> 1 iff X is non-zero power of 2. Maybe better also to just + // return icmp X, 0 if its known power of 2 but not known non-zero. + if (IC.isKnownToBeAPowerOfTwo(Op0, /* OrZero */ false)) + return IC.replaceInstUsesWith(II, ConstantInt::get(Ty, 1)); + // ctpop(bitreverse(x)) -> ctpop(x) // ctpop(bswap(x)) -> ctpop(x) if (match(Op0, m_BitReverse(m_Value(X))) || match(Op0, m_BSwap(m_Value(X)))) diff --git a/llvm/test/Transforms/InstCombine/ctpop-pow2.ll b/llvm/test/Transforms/InstCombine/ctpop-pow2.ll --- a/llvm/test/Transforms/InstCombine/ctpop-pow2.ll +++ b/llvm/test/Transforms/InstCombine/ctpop-pow2.ll @@ -10,9 +10,7 @@ define i64 @ctpop_1_shl(i64 %x) { ; CHECK-LABEL: @ctpop_1_shl( -; CHECK-NEXT: [[V:%.*]] = shl nuw i64 1, [[X:%.*]] -; CHECK-NEXT: [[CNT:%.*]] = call i64 @llvm.ctpop.i64(i64 [[V]]), !range [[RNG0:![0-9]+]] -; CHECK-NEXT: ret i64 [[CNT]] +; CHECK-NEXT: ret i64 1 ; %v = shl i64 1, %x %cnt = call i64 @llvm.ctpop.i64(i64 %v) @@ -21,9 +19,7 @@ define i32 @ctpop_imin_lshr(i32 %x) { ; CHECK-LABEL: @ctpop_imin_lshr( -; CHECK-NEXT: [[V:%.*]] = lshr i32 -2147483648, [[X:%.*]] -; CHECK-NEXT: [[CNT:%.*]] = call i32 @llvm.ctpop.i32(i32 [[V]]), !range [[RNG1:![0-9]+]] -; CHECK-NEXT: ret i32 [[CNT]] +; CHECK-NEXT: ret i32 1 ; %v = lshr i32 2147483648, %x %cnt = call i32 @llvm.ctpop.i32(i32 %v) @@ -34,7 +30,7 @@ ; CHECK-LABEL: @ctpop_x_and_negx( ; CHECK-NEXT: [[V0:%.*]] = sub i16 0, [[X:%.*]] ; CHECK-NEXT: [[V1:%.*]] = and i16 [[V0]], [[X]] -; CHECK-NEXT: [[CNT:%.*]] = call i16 @llvm.ctpop.i16(i16 [[V1]]), !range [[RNG2:![0-9]+]] +; CHECK-NEXT: [[CNT:%.*]] = call i16 @llvm.ctpop.i16(i16 [[V1]]), !range [[RNG0:![0-9]+]] ; CHECK-NEXT: ret i16 [[CNT]] ; %v0 = sub i16 0, %x @@ -48,7 +44,7 @@ ; CHECK-NEXT: [[X1:%.*]] = or i8 [[X:%.*]], 1 ; CHECK-NEXT: [[V0:%.*]] = sub nsw i8 0, [[X1]] ; CHECK-NEXT: [[V1:%.*]] = and i8 [[X1]], [[V0]] -; CHECK-NEXT: [[CNT:%.*]] = call i8 @llvm.ctpop.i8(i8 [[V1]]), !range [[RNG3:![0-9]+]] +; CHECK-NEXT: [[CNT:%.*]] = call i8 @llvm.ctpop.i8(i8 [[V1]]), !range [[RNG1:![0-9]+]] ; CHECK-NEXT: ret i8 [[CNT]] ; %x1 = or i8 %x, 1 @@ -61,7 +57,7 @@ define i32 @ctpop_2_shl(i32 %x) { ; CHECK-LABEL: @ctpop_2_shl( ; CHECK-NEXT: [[V:%.*]] = shl i32 2, [[X:%.*]] -; CHECK-NEXT: [[CNT:%.*]] = call i32 @llvm.ctpop.i32(i32 [[V]]), !range [[RNG4:![0-9]+]] +; CHECK-NEXT: [[CNT:%.*]] = call i32 @llvm.ctpop.i32(i32 [[V]]), !range [[RNG2:![0-9]+]] ; CHECK-NEXT: ret i32 [[CNT]] ; %v = shl i32 2, %x @@ -72,7 +68,7 @@ define i16 @ctpop_imin_plus1_lshr(i16 %x) { ; CHECK-LABEL: @ctpop_imin_plus1_lshr( ; CHECK-NEXT: [[V:%.*]] = lshr i16 -32767, [[X:%.*]] -; CHECK-NEXT: [[CNT:%.*]] = call i16 @llvm.ctpop.i16(i16 [[V]]), !range [[RNG2]] +; CHECK-NEXT: [[CNT:%.*]] = call i16 @llvm.ctpop.i16(i16 [[V]]), !range [[RNG0]] ; CHECK-NEXT: ret i16 [[CNT]] ; %v = lshr i16 32769, %x @@ -85,7 +81,7 @@ ; CHECK-LABEL: @ctpop_2_shl_nz( ; CHECK-NEXT: [[XA30:%.*]] = and i32 [[X:%.*]], 30 ; CHECK-NEXT: [[V:%.*]] = shl i32 2, [[XA30]] -; CHECK-NEXT: [[CNT:%.*]] = call i32 @llvm.ctpop.i32(i32 [[V]]), !range [[RNG5:![0-9]+]] +; CHECK-NEXT: [[CNT:%.*]] = call i32 @llvm.ctpop.i32(i32 [[V]]), !range [[RNG3:![0-9]+]] ; CHECK-NEXT: ret i32 [[CNT]] ; %xa30 = and i32 30, %x @@ -99,7 +95,7 @@ ; 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 i8 @llvm.ctpop.i8(i8 [[V]]), !range [[RNG6:![0-9]+]] +; CHECK-NEXT: [[CNT:%.*]] = call i8 @llvm.ctpop.i8(i8 [[V]]), !range [[RNG4:![0-9]+]] ; CHECK-NEXT: ret i8 [[CNT]] ; %cmp = icmp ne i8 %x, 0 @@ -116,7 +112,7 @@ ; CHECK-NEXT: [[V1:%.*]] = and i64 [[V0]], [[X]] ; CHECK-NEXT: [[CMP:%.*]] = icmp ne i64 [[V1]], 0 ; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]]) -; CHECK-NEXT: [[CNT:%.*]] = call i64 @llvm.ctpop.i64(i64 [[V1]]), !range [[RNG0]] +; CHECK-NEXT: [[CNT:%.*]] = call i64 @llvm.ctpop.i64(i64 [[V1]]), !range [[RNG5:![0-9]+]] ; CHECK-NEXT: ret i64 [[CNT]] ; %v0 = sub i64 0, %x @@ -129,9 +125,7 @@ define <2 x i32> @ctpop_shl1_vec(<2 x i32> %x) { ; CHECK-LABEL: @ctpop_shl1_vec( -; CHECK-NEXT: [[SHL:%.*]] = shl nuw <2 x i32> , [[X:%.*]] -; CHECK-NEXT: [[CNT:%.*]] = call <2 x i32> @llvm.ctpop.v2i32(<2 x i32> [[SHL]]) -; CHECK-NEXT: ret <2 x i32> [[CNT]] +; CHECK-NEXT: ret <2 x i32> ; %shl = shl <2 x i32> , %x %cnt = call <2 x i32> @llvm.ctpop.v2i32(<2 x i32> %shl) @@ -151,9 +145,7 @@ define <2 x i32> @ctpop_lshr_intmin_vec(<2 x i32> %x) { ; CHECK-LABEL: @ctpop_lshr_intmin_vec( -; CHECK-NEXT: [[SHR:%.*]] = lshr <2 x i32> , [[X:%.*]] -; CHECK-NEXT: [[CNT:%.*]] = call <2 x i32> @llvm.ctpop.v2i32(<2 x i32> [[SHR]]) -; CHECK-NEXT: ret <2 x i32> [[CNT]] +; CHECK-NEXT: ret <2 x i32> ; %shr = lshr <2 x i32> , %x %cnt = call <2 x i32> @llvm.ctpop.v2i32(<2 x i32> %shr)