[llvm] 7cbfc39 - [InstCombine] reduce compare of signbits of 2 values

Sanjay Patel via llvm-commits llvm-commits at lists.llvm.org
Tue Jan 24 05:47:49 PST 2023


Author: Sanjay Patel
Date: 2023-01-24T08:47:41-05:00
New Revision: 7cbfc39c77cafe925c0599ab121a67f94bf3870a

URL: https://github.com/llvm/llvm-project/commit/7cbfc39c77cafe925c0599ab121a67f94bf3870a
DIFF: https://github.com/llvm/llvm-project/commit/7cbfc39c77cafe925c0599ab121a67f94bf3870a.diff

LOG: [InstCombine] reduce compare of signbits of 2 values

Test if 2 values have different or same signbits:
(X u>> BitWidth - 1) == zext (Y s> -1) --> (X ^ Y) < 0
(X u>> BitWidth - 1) != zext (Y s> -1) --> (X ^ Y) > -1

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

As noted in #60242, these patterns regressed between the
14.0 and 15.0 releases - probably due to a change in
canonicalization of related patterns.

The related patterns for testing if 2 values are both
pos/neg appear to be handled already.

Added: 
    

Modified: 
    llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
    llvm/test/Transforms/InstCombine/icmp-shr.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index c3a53df5fb4d6..1480a0ff9e2f8 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -4653,14 +4653,30 @@ Instruction *InstCombinerImpl::foldICmpEquality(ICmpInst &I) {
     }
   }
 
-  // (B & (Pow2C-1)) == zext A --> A == trunc B
-  // (B & (Pow2C-1)) != zext A --> A != trunc B
-  const APInt *MaskC;
-  if (match(Op0, m_And(m_Value(B), m_LowBitMask(MaskC))) &&
-      match(Op1, m_ZExt(m_Value(A))) &&
-      MaskC->countTrailingOnes() == A->getType()->getScalarSizeInBits() &&
-      (Op0->hasOneUse() || Op1->hasOneUse()))
-    return new ICmpInst(Pred, A, Builder.CreateTrunc(B, A->getType()));
+  if (match(Op1, m_ZExt(m_Value(A))) &&
+      (Op0->hasOneUse() || Op1->hasOneUse())) {
+    // (B & (Pow2C-1)) == zext A --> A == trunc B
+    // (B & (Pow2C-1)) != zext A --> A != trunc B
+    const APInt *MaskC;
+    if (match(Op0, m_And(m_Value(B), m_LowBitMask(MaskC))) &&
+        MaskC->countTrailingOnes() == A->getType()->getScalarSizeInBits())
+      return new ICmpInst(Pred, A, Builder.CreateTrunc(B, A->getType()));
+
+    // Test if 2 values have 
diff erent or same signbits:
+    // (X u>> BitWidth - 1) == zext (Y s> -1) --> (X ^ Y) < 0
+    // (X u>> BitWidth - 1) != zext (Y s> -1) --> (X ^ Y) > -1
+    unsigned OpWidth = Op0->getType()->getScalarSizeInBits();
+    Value *X, *Y;
+    ICmpInst::Predicate Pred2;
+    if (match(Op0, m_LShr(m_Value(X), m_SpecificIntAllowUndef(OpWidth - 1))) &&
+        match(A, m_ICmp(Pred2, m_Value(Y), m_AllOnes())) &&
+        Pred2 == ICmpInst::ICMP_SGT && X->getType() == Y->getType()) {
+      Value *Xor = Builder.CreateXor(X, Y, "xor.signbits");
+      Value *R = (Pred == ICmpInst::ICMP_EQ) ? Builder.CreateIsNeg(Xor) :
+                                               Builder.CreateIsNotNeg(Xor);
+      return replaceInstUsesWith(I, R);
+    }
+  }
 
   // (A >> C) == (B >> C) --> (A^B) u< (1 << C)
   // For lshr and ashr pairs.

diff  --git a/llvm/test/Transforms/InstCombine/icmp-shr.ll b/llvm/test/Transforms/InstCombine/icmp-shr.ll
index 2b775bd365270..e60f08cf22358 100644
--- a/llvm/test/Transforms/InstCombine/icmp-shr.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-shr.ll
@@ -1302,10 +1302,8 @@ define i1 @lshr_neg_sgt_zero(i8 %x) {
 
 define i1 @exactly_one_set_signbit(i8 %x, i8 %y) {
 ; CHECK-LABEL: @exactly_one_set_signbit(
-; CHECK-NEXT:    [[XSIGN:%.*]] = lshr i8 [[X:%.*]], 7
-; CHECK-NEXT:    [[YPOS:%.*]] = icmp sgt i8 [[Y:%.*]], -1
-; CHECK-NEXT:    [[YPOSZ:%.*]] = zext i1 [[YPOS]] to i8
-; CHECK-NEXT:    [[R:%.*]] = icmp eq i8 [[XSIGN]], [[YPOSZ]]
+; CHECK-NEXT:    [[XOR_SIGNBITS:%.*]] = xor i8 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp slt i8 [[XOR_SIGNBITS]], 0
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %xsign = lshr i8 %x, 7
@@ -1319,9 +1317,8 @@ define i1 @exactly_one_set_signbit_use1(i8 %x, i8 %y) {
 ; CHECK-LABEL: @exactly_one_set_signbit_use1(
 ; CHECK-NEXT:    [[XSIGN:%.*]] = lshr i8 [[X:%.*]], 7
 ; CHECK-NEXT:    call void @use(i8 [[XSIGN]])
-; CHECK-NEXT:    [[YPOS:%.*]] = icmp sgt i8 [[Y:%.*]], -1
-; CHECK-NEXT:    [[YPOSZ:%.*]] = zext i1 [[YPOS]] to i8
-; CHECK-NEXT:    [[R:%.*]] = icmp eq i8 [[XSIGN]], [[YPOSZ]]
+; CHECK-NEXT:    [[XOR_SIGNBITS:%.*]] = xor i8 [[X]], [[Y:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp slt i8 [[XOR_SIGNBITS]], 0
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %xsign = lshr i8 %x, 7
@@ -1334,10 +1331,8 @@ define i1 @exactly_one_set_signbit_use1(i8 %x, i8 %y) {
 
 define <2 x i1> @same_signbit(<2 x i8> %x, <2 x i8> %y) {
 ; CHECK-LABEL: @same_signbit(
-; CHECK-NEXT:    [[XSIGN:%.*]] = lshr <2 x i8> [[X:%.*]], <i8 7, i8 7>
-; CHECK-NEXT:    [[YPOS:%.*]] = icmp sgt <2 x i8> [[Y:%.*]], <i8 -1, i8 -1>
-; CHECK-NEXT:    [[YPOSZ:%.*]] = zext <2 x i1> [[YPOS]] to <2 x i8>
-; CHECK-NEXT:    [[R:%.*]] = icmp ne <2 x i8> [[XSIGN]], [[YPOSZ]]
+; CHECK-NEXT:    [[XOR_SIGNBITS:%.*]] = xor <2 x i8> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp sgt <2 x i8> [[XOR_SIGNBITS]], <i8 -1, i8 -1>
 ; CHECK-NEXT:    ret <2 x i1> [[R]]
 ;
   %xsign = lshr <2 x i8> %x, <i8 7, i8 7>
@@ -1349,11 +1344,11 @@ define <2 x i1> @same_signbit(<2 x i8> %x, <2 x i8> %y) {
 
 define i1 @same_signbit_use2(i8 %x, i8 %y) {
 ; CHECK-LABEL: @same_signbit_use2(
-; CHECK-NEXT:    [[XSIGN:%.*]] = lshr i8 [[X:%.*]], 7
 ; CHECK-NEXT:    [[YPOS:%.*]] = icmp sgt i8 [[Y:%.*]], -1
 ; CHECK-NEXT:    [[YPOSZ:%.*]] = zext i1 [[YPOS]] to i8
 ; CHECK-NEXT:    call void @use(i8 [[YPOSZ]])
-; CHECK-NEXT:    [[R:%.*]] = icmp ne i8 [[XSIGN]], [[YPOSZ]]
+; CHECK-NEXT:    [[XOR_SIGNBITS:%.*]] = xor i8 [[X:%.*]], [[Y]]
+; CHECK-NEXT:    [[R:%.*]] = icmp sgt i8 [[XOR_SIGNBITS]], -1
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %xsign = lshr i8 %x, 7
@@ -1364,6 +1359,8 @@ define i1 @same_signbit_use2(i8 %x, i8 %y) {
   ret i1 %r
 }
 
+; negative test
+
 define i1 @same_signbit_use3(i8 %x, i8 %y) {
 ; CHECK-LABEL: @same_signbit_use3(
 ; CHECK-NEXT:    [[XSIGN:%.*]] = lshr i8 [[X:%.*]], 7
@@ -1385,10 +1382,8 @@ define i1 @same_signbit_use3(i8 %x, i8 %y) {
 
 define <2 x i1> @same_signbit_poison_elts(<2 x i8> %x, <2 x i8> %y) {
 ; CHECK-LABEL: @same_signbit_poison_elts(
-; CHECK-NEXT:    [[XSIGN:%.*]] = lshr <2 x i8> [[X:%.*]], <i8 7, i8 poison>
-; CHECK-NEXT:    [[YPOS:%.*]] = icmp sgt <2 x i8> [[Y:%.*]], <i8 -1, i8 poison>
-; CHECK-NEXT:    [[YPOSZ:%.*]] = zext <2 x i1> [[YPOS]] to <2 x i8>
-; CHECK-NEXT:    [[R:%.*]] = icmp ne <2 x i8> [[XSIGN]], [[YPOSZ]]
+; CHECK-NEXT:    [[XOR_SIGNBITS:%.*]] = xor <2 x i8> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp sgt <2 x i8> [[XOR_SIGNBITS]], <i8 -1, i8 -1>
 ; CHECK-NEXT:    ret <2 x i1> [[R]]
 ;
   %xsign = lshr <2 x i8> %x, <i8 7, i8 poison>
@@ -1398,6 +1393,8 @@ define <2 x i1> @same_signbit_poison_elts(<2 x i8> %x, <2 x i8> %y) {
   ret <2 x i1> %r
 }
 
+; negative test
+
 define i1 @same_signbit_wrong_type(i8 %x, i32 %y) {
 ; CHECK-LABEL: @same_signbit_wrong_type(
 ; CHECK-NEXT:    [[XSIGN:%.*]] = lshr i8 [[X:%.*]], 7
@@ -1412,6 +1409,9 @@ define i1 @same_signbit_wrong_type(i8 %x, i32 %y) {
   %r = icmp ne i8 %xsign, %yposz
   ret i1 %r
 }
+
+; negative test
+
 define i1 @exactly_one_set_signbit_wrong_shamt(i8 %x, i8 %y) {
 ; CHECK-LABEL: @exactly_one_set_signbit_wrong_shamt(
 ; CHECK-NEXT:    [[XSIGN:%.*]] = lshr i8 [[X:%.*]], 6
@@ -1427,6 +1427,9 @@ define i1 @exactly_one_set_signbit_wrong_shamt(i8 %x, i8 %y) {
   ret i1 %r
 }
 
+; negative test
+; TODO: This could reduce.
+
 define i1 @exactly_one_set_signbit_wrong_shr(i8 %x, i8 %y) {
 ; CHECK-LABEL: @exactly_one_set_signbit_wrong_shr(
 ; CHECK-NEXT:    [[XSIGN:%.*]] = ashr i8 [[X:%.*]], 7
@@ -1442,6 +1445,9 @@ define i1 @exactly_one_set_signbit_wrong_shr(i8 %x, i8 %y) {
   ret i1 %r
 }
 
+; negative test
+; TODO: This could reduce.
+
 define i1 @exactly_one_set_signbit_wrong_pred(i8 %x, i8 %y) {
 ; CHECK-LABEL: @exactly_one_set_signbit_wrong_pred(
 ; CHECK-NEXT:    [[XSIGN:%.*]] = lshr i8 [[X:%.*]], 7


        


More information about the llvm-commits mailing list