[InstSimplify] remove ctpop of 1 (low) bit
authorSanjay Patel <spatel@rotateright.com>
Mon, 28 Dec 2020 20:00:03 +0000 (15:00 -0500)
committerSanjay Patel <spatel@rotateright.com>
Mon, 28 Dec 2020 21:06:20 +0000 (16:06 -0500)
https://llvm.org/PR48608

As noted in the test comment, we could handle a more general
case in instcombine and remove this, but I don't have evidence
that we need to do that.

https://alive2.llvm.org/ce/z/MRW9gD

llvm/lib/Analysis/InstructionSimplify.cpp
llvm/test/Transforms/InstCombine/ctpop.ll
llvm/test/Transforms/InstSimplify/call.ll

index 27b73a5..30c7ecf 100644 (file)
@@ -5246,6 +5246,15 @@ static Value *simplifyUnaryIntrinsic(Function *F, Value *Op0,
     // bitreverse(bitreverse(x)) -> x
     if (match(Op0, m_BitReverse(m_Value(X)))) return X;
     break;
+  case Intrinsic::ctpop: {
+    // If everything but the lowest bit is zero, that bit is the pop-count. Ex:
+    // ctpop(and X, 1) --> and X, 1
+    unsigned BitWidth = Op0->getType()->getScalarSizeInBits();
+    if (MaskedValueIsZero(Op0, APInt::getHighBitsSet(BitWidth, BitWidth - 1),
+                          Q.DL, 0, Q.AC, Q.CxtI, Q.DT))
+      return Op0;
+    break;
+  }
   case Intrinsic::exp:
     // exp(log(x)) -> x
     if (Q.CxtI->hasAllowReassoc() &&
index 33b95b0..237fb04 100644 (file)
@@ -84,11 +84,11 @@ define <2 x i1> @test5vec(<2 x i32> %arg) {
   ret <2 x i1> %res
 }
 
-; Make sure we don't add range metadata to i1 ctpop.
+; No intrinsic or range needed - ctpop of bool bit is the bit itself.
+
 define i1 @test6(i1 %arg) {
 ; CHECK-LABEL: @test6(
-; CHECK-NEXT:    [[CNT:%.*]] = call i1 @llvm.ctpop.i1(i1 [[ARG:%.*]])
-; CHECK-NEXT:    ret i1 [[CNT]]
+; CHECK-NEXT:    ret i1 [[ARG:%.*]]
 ;
   %cnt = call i1 @llvm.ctpop.i1(i1 %arg)
   ret i1 %cnt
index fa73e07..841582a 100644 (file)
@@ -1308,14 +1308,16 @@ declare i1 @llvm.ctpop.i1(i1)
 define i32 @ctpop_lowbit(i32 %x) {
 ; CHECK-LABEL: @ctpop_lowbit(
 ; CHECK-NEXT:    [[B:%.*]] = and i32 [[X:%.*]], 1
-; CHECK-NEXT:    [[R:%.*]] = call i32 @llvm.ctpop.i32(i32 [[B]])
-; CHECK-NEXT:    ret i32 [[R]]
+; CHECK-NEXT:    ret i32 [[B]]
 ;
   %b = and i32 %x, 1
   %r = call i32 @llvm.ctpop.i32(i32 %b)
   ret i32 %r
 }
 
+; Negative test - only low bit allowed
+; This could be reduced by instcombine to and+shift.
+
 define i32 @ctpop_pow2(i32 %x) {
 ; CHECK-LABEL: @ctpop_pow2(
 ; CHECK-NEXT:    [[B:%.*]] = and i32 [[X:%.*]], 4
@@ -1330,14 +1332,15 @@ define i32 @ctpop_pow2(i32 %x) {
 define <3 x i33> @ctpop_signbit(<3 x i33> %x) {
 ; CHECK-LABEL: @ctpop_signbit(
 ; CHECK-NEXT:    [[B:%.*]] = lshr <3 x i33> [[X:%.*]], <i33 32, i33 32, i33 32>
-; CHECK-NEXT:    [[R:%.*]] = tail call <3 x i33> @llvm.ctpop.v3i33(<3 x i33> [[B]])
-; CHECK-NEXT:    ret <3 x i33> [[R]]
+; CHECK-NEXT:    ret <3 x i33> [[B]]
 ;
   %b = lshr <3 x i33> %x, <i33 32, i33 32, i33 32>
   %r = tail call <3 x i33> @llvm.ctpop.v3i33(<3 x i33> %b)
   ret <3 x i33> %r
 }
 
+; Negative test - only 1 bit allowed
+
 define <3 x i33> @ctpop_notsignbit(<3 x i33> %x) {
 ; CHECK-LABEL: @ctpop_notsignbit(
 ; CHECK-NEXT:    [[B:%.*]] = lshr <3 x i33> [[X:%.*]], <i33 31, i33 31, i33 31>
@@ -1351,8 +1354,7 @@ define <3 x i33> @ctpop_notsignbit(<3 x i33> %x) {
 
 define i1 @ctpop_bool(i1 %x) {
 ; CHECK-LABEL: @ctpop_bool(
-; CHECK-NEXT:    [[R:%.*]] = tail call i1 @llvm.ctpop.i1(i1 [[X:%.*]])
-; CHECK-NEXT:    ret i1 [[R]]
+; CHECK-NEXT:    ret i1 [[X:%.*]]
 ;
   %r = tail call i1 @llvm.ctpop.i1(i1 %x)
   ret i1 %r