[llvm] 53eede5 - [InstCombine] look through 'not' of ctlz/cttz op with 0-is-undef

Sanjay Patel via llvm-commits llvm-commits at lists.llvm.org
Mon Sep 12 12:24:45 PDT 2022


Author: Sanjay Patel
Date: 2022-09-12T15:06:21-04:00
New Revision: 53eede597e8423410ec48b7c335c76f3b6c4c714

URL: https://github.com/llvm/llvm-project/commit/53eede597e8423410ec48b7c335c76f3b6c4c714
DIFF: https://github.com/llvm/llvm-project/commit/53eede597e8423410ec48b7c335c76f3b6c4c714.diff

LOG: [InstCombine] look through 'not' of ctlz/cttz op with 0-is-undef

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

This pattern was flagged at:
https://discourse.llvm.org/t/instcombines-select-optimizations-dont-trigger-reliably/64927

Added: 
    

Modified: 
    llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
    llvm/test/Transforms/InstCombine/select-cmp-cttz-ctlz.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index 98cf450a95268..fc1a43535e350 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -952,8 +952,8 @@ static Value *foldSelectCttzCtlz(ICmpInst *ICI, Value *TrueVal, Value *FalseVal,
   Value *CmpLHS = ICI->getOperand(0);
   Value *CmpRHS = ICI->getOperand(1);
 
-  // Check if the condition value compares a value for equality against zero.
-  if (!ICI->isEquality() || !match(CmpRHS, m_Zero()))
+  // Check if the select condition compares a value for equality.
+  if (!ICI->isEquality())
     return nullptr;
 
   Value *SelectArg = FalseVal;
@@ -969,8 +969,15 @@ static Value *foldSelectCttzCtlz(ICmpInst *ICI, Value *TrueVal, Value *FalseVal,
 
   // Check that 'Count' is a call to intrinsic cttz/ctlz. Also check that the
   // input to the cttz/ctlz is used as LHS for the compare instruction.
-  if (!match(Count, m_Intrinsic<Intrinsic::cttz>(m_Specific(CmpLHS))) &&
-      !match(Count, m_Intrinsic<Intrinsic::ctlz>(m_Specific(CmpLHS))))
+  Value *X;
+  if (!match(Count, m_Intrinsic<Intrinsic::cttz>(m_Value(X))) &&
+      !match(Count, m_Intrinsic<Intrinsic::ctlz>(m_Value(X))))
+    return nullptr;
+
+  // (X == 0) ? BitWidth : ctz(X)
+  // (X == -1) ? BitWidth : ctz(~X)
+  if ((X != CmpLHS || !match(CmpRHS, m_Zero())) &&
+      (!match(X, m_Not(m_Specific(CmpLHS))) || !match(CmpRHS, m_AllOnes())))
     return nullptr;
 
   IntrinsicInst *II = cast<IntrinsicInst>(Count);

diff  --git a/llvm/test/Transforms/InstCombine/select-cmp-cttz-ctlz.ll b/llvm/test/Transforms/InstCombine/select-cmp-cttz-ctlz.ll
index 8fe2a005806a8..4dff0ccc9400f 100644
--- a/llvm/test/Transforms/InstCombine/select-cmp-cttz-ctlz.ll
+++ b/llvm/test/Transforms/InstCombine/select-cmp-cttz-ctlz.ll
@@ -287,13 +287,45 @@ define i32 @test5d(i64 %x) {
 define i32 @not_op_ctlz(i64 %x) {
 ; CHECK-LABEL: @not_op_ctlz(
 ; CHECK-NEXT:    [[N:%.*]] = xor i64 [[X:%.*]], -1
+; CHECK-NEXT:    [[CT:%.*]] = tail call i64 @llvm.ctlz.i64(i64 [[N]], i1 false), !range [[RNG2]]
+; CHECK-NEXT:    [[CAST:%.*]] = trunc i64 [[CT]] to i32
+; CHECK-NEXT:    ret i32 [[CAST]]
+;
+  %n = xor i64 %x, -1
+  %ct = tail call i64 @llvm.ctlz.i64(i64 %n, i1 true)
+  %cast = trunc i64 %ct to i32
+  %tobool = icmp eq i64 %x, -1
+  %r = select i1 %tobool, i32 64, i32 %cast
+  ret i32 %r
+}
+
+define i32 @not_op_cttz(i64 %x) {
+; CHECK-LABEL: @not_op_cttz(
+; CHECK-NEXT:    [[N:%.*]] = xor i64 [[X:%.*]], -1
+; CHECK-NEXT:    [[CT:%.*]] = tail call i64 @llvm.cttz.i64(i64 [[N]], i1 false), !range [[RNG2]]
+; CHECK-NEXT:    [[CAST:%.*]] = trunc i64 [[CT]] to i32
+; CHECK-NEXT:    ret i32 [[CAST]]
+;
+  %n = xor i64 %x, -1
+  %ct = tail call i64 @llvm.cttz.i64(i64 %n, i1 true)
+  %cast = trunc i64 %ct to i32
+  %tobool = icmp eq i64 %x, -1
+  %r = select i1 %tobool, i32 64, i32 %cast
+  ret i32 %r
+}
+
+; negative test
+
+define i32 @not_op_ctlz_wrong_xor_op1(i64 %x) {
+; CHECK-LABEL: @not_op_ctlz_wrong_xor_op1(
+; CHECK-NEXT:    [[N:%.*]] = xor i64 [[X:%.*]], -2
 ; CHECK-NEXT:    [[CT:%.*]] = tail call i64 @llvm.ctlz.i64(i64 [[N]], i1 true), !range [[RNG2]]
 ; CHECK-NEXT:    [[CAST:%.*]] = trunc i64 [[CT]] to i32
 ; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp eq i64 [[X]], -1
 ; CHECK-NEXT:    [[R:%.*]] = select i1 [[TOBOOL]], i32 64, i32 [[CAST]]
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
-  %n = xor i64 %x, -1
+  %n = xor i64 %x, -2
   %ct = tail call i64 @llvm.ctlz.i64(i64 %n, i1 true)
   %cast = trunc i64 %ct to i32
   %tobool = icmp eq i64 %x, -1
@@ -301,19 +333,40 @@ define i32 @not_op_ctlz(i64 %x) {
   ret i32 %r
 }
 
-define i32 @not_op_cttz(i64 %x) {
-; CHECK-LABEL: @not_op_cttz(
+; negative test
+
+define i32 @not_op_ctlz_wrong_xor_op0(i64 %x, i64 %y) {
+; CHECK-LABEL: @not_op_ctlz_wrong_xor_op0(
+; CHECK-NEXT:    [[N:%.*]] = xor i64 [[Y:%.*]], -1
+; CHECK-NEXT:    [[CT:%.*]] = tail call i64 @llvm.ctlz.i64(i64 [[N]], i1 true), !range [[RNG2]]
+; CHECK-NEXT:    [[CAST:%.*]] = trunc i64 [[CT]] to i32
+; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp eq i64 [[X:%.*]], -1
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[TOBOOL]], i32 64, i32 [[CAST]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %n = xor i64 %y, -1
+  %ct = tail call i64 @llvm.ctlz.i64(i64 %n, i1 true)
+  %cast = trunc i64 %ct to i32
+  %tobool = icmp eq i64 %x, -1
+  %r = select i1 %tobool, i32 64, i32 %cast
+  ret i32 %r
+}
+
+; negative test
+
+define i32 @not_op_cttz_wrong_cmp(i64 %x) {
+; CHECK-LABEL: @not_op_cttz_wrong_cmp(
 ; CHECK-NEXT:    [[N:%.*]] = xor i64 [[X:%.*]], -1
 ; CHECK-NEXT:    [[CT:%.*]] = tail call i64 @llvm.cttz.i64(i64 [[N]], i1 true), !range [[RNG2]]
 ; CHECK-NEXT:    [[CAST:%.*]] = trunc i64 [[CT]] to i32
-; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp eq i64 [[X]], -1
+; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp eq i64 [[X]], 0
 ; CHECK-NEXT:    [[R:%.*]] = select i1 [[TOBOOL]], i32 64, i32 [[CAST]]
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
   %n = xor i64 %x, -1
   %ct = tail call i64 @llvm.cttz.i64(i64 %n, i1 true)
   %cast = trunc i64 %ct to i32
-  %tobool = icmp eq i64 %x, -1
+  %tobool = icmp eq i64 %x, 0
   %r = select i1 %tobool, i32 64, i32 %cast
   ret i32 %r
 }


        


More information about the llvm-commits mailing list