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 @@ -9,9 +9,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) @@ -20,9 +18,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) @@ -33,7 +29,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 @@ -47,7 +43,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 @@ -60,7 +56,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 @@ -71,7 +67,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 @@ -84,7 +80,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 @@ -98,7 +94,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 @@ -115,7 +111,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