[llvm] 0ef7cbc - [InstCombine] reduce compare of signbits of 2 values, signed variant

Sanjay Patel via llvm-commits llvm-commits at lists.llvm.org
Thu Jan 26 05:58:59 PST 2023


Author: Sanjay Patel
Date: 2023-01-26T08:58:45-05:00
New Revision: 0ef7cbc319ee6488a47fda1b45b0d7170722df31

URL: https://github.com/llvm/llvm-project/commit/0ef7cbc319ee6488a47fda1b45b0d7170722df31
DIFF: https://github.com/llvm/llvm-project/commit/0ef7cbc319ee6488a47fda1b45b0d7170722df31.diff

LOG: [InstCombine] reduce compare of signbits of 2 values, signed variant

(X s>> BitWidth - 1) == sext (Y s> -1) --> (X ^ Y) < 0
(X s>> BitWidth - 1) != sext (Y s> -1) --> (X ^ Y) > -1

This is the same logic as:
7cbfc39c77ca
...extended to deal with "signed" cast+shift instructions.

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

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 1480a0ff9e2f..8e90014d24d8 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -4661,20 +4661,34 @@ Instruction *InstCombinerImpl::foldICmpEquality(ICmpInst &I) {
     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
+  // 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
+  // (X s>> BitWidth - 1) == sext (Y s> -1) --> (X ^ Y) < 0
+  // (X s>> BitWidth - 1) != sext (Y s> -1) --> (X ^ Y) > -1
+  Instruction *ExtI;
+  if (match(Op1, m_CombineAnd(m_Instruction(ExtI), m_ZExtOrSExt(m_Value(A)))) &&
+      (Op0->hasOneUse() || Op1->hasOneUse())) {
     unsigned OpWidth = Op0->getType()->getScalarSizeInBits();
+    Instruction *ShiftI;
     Value *X, *Y;
     ICmpInst::Predicate Pred2;
-    if (match(Op0, m_LShr(m_Value(X), m_SpecificIntAllowUndef(OpWidth - 1))) &&
+    if (match(Op0, m_CombineAnd(m_Instruction(ShiftI),
+                                m_Shr(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);
+      unsigned ExtOpc = ExtI->getOpcode();
+      unsigned ShiftOpc = ShiftI->getOpcode();
+      if ((ExtOpc == Instruction::ZExt && ShiftOpc == Instruction::LShr) ||
+          (ExtOpc == Instruction::SExt && ShiftOpc == Instruction::AShr)) {
+        Value *Xor = Builder.CreateXor(X, Y, "xor.signbits");
+        Value *R = (Pred == ICmpInst::ICMP_EQ) ? Builder.CreateIsNeg(Xor)
+                                               : Builder.CreateIsNotNeg(Xor);
+        return replaceInstUsesWith(I, R);
+      }
     }
   }
 

diff  --git a/llvm/test/Transforms/InstCombine/icmp-shr.ll b/llvm/test/Transforms/InstCombine/icmp-shr.ll
index 0259e601fafa..f4dfa2edfa17 100644
--- a/llvm/test/Transforms/InstCombine/icmp-shr.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-shr.ll
@@ -1465,10 +1465,8 @@ define i1 @exactly_one_set_signbit_wrong_pred(i8 %x, i8 %y) {
 
 define i1 @exactly_one_set_signbit_signed(i8 %x, i8 %y) {
 ; CHECK-LABEL: @exactly_one_set_signbit_signed(
-; CHECK-NEXT:    [[XSIGN:%.*]] = ashr i8 [[X:%.*]], 7
-; CHECK-NEXT:    [[YPOS:%.*]] = icmp sgt i8 [[Y:%.*]], -1
-; CHECK-NEXT:    [[YPOSZ:%.*]] = sext 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 = ashr i8 %x, 7
@@ -1482,9 +1480,8 @@ define i1 @exactly_one_set_signbit_use1_signed(i8 %x, i8 %y) {
 ; CHECK-LABEL: @exactly_one_set_signbit_use1_signed(
 ; CHECK-NEXT:    [[XSIGN:%.*]] = ashr i8 [[X:%.*]], 7
 ; CHECK-NEXT:    call void @use(i8 [[XSIGN]])
-; CHECK-NEXT:    [[YPOS:%.*]] = icmp sgt i8 [[Y:%.*]], -1
-; CHECK-NEXT:    [[YPOSZ:%.*]] = sext 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 = ashr i8 %x, 7
@@ -1497,10 +1494,8 @@ define i1 @exactly_one_set_signbit_use1_signed(i8 %x, i8 %y) {
 
 define <2 x i1> @same_signbit_signed(<2 x i8> %x, <2 x i8> %y) {
 ; CHECK-LABEL: @same_signbit_signed(
-; CHECK-NEXT:    [[XSIGN:%.*]] = ashr <2 x i8> [[X:%.*]], <i8 7, i8 7>
-; CHECK-NEXT:    [[YPOS:%.*]] = icmp sgt <2 x i8> [[Y:%.*]], <i8 -1, i8 -1>
-; CHECK-NEXT:    [[YPOSZ:%.*]] = sext <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 = ashr <2 x i8> %x, <i8 7, i8 7>
@@ -1512,11 +1507,11 @@ define <2 x i1> @same_signbit_signed(<2 x i8> %x, <2 x i8> %y) {
 
 define i1 @same_signbit_use2_signed(i8 %x, i8 %y) {
 ; CHECK-LABEL: @same_signbit_use2_signed(
-; CHECK-NEXT:    [[XSIGN:%.*]] = ashr i8 [[X:%.*]], 7
 ; CHECK-NEXT:    [[YPOS:%.*]] = icmp sgt i8 [[Y:%.*]], -1
 ; CHECK-NEXT:    [[YPOSZ:%.*]] = sext 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 = ashr i8 %x, 7
@@ -1527,6 +1522,8 @@ define i1 @same_signbit_use2_signed(i8 %x, i8 %y) {
   ret i1 %r
 }
 
+; negative test
+
 define i1 @same_signbit_use3_signed(i8 %x, i8 %y) {
 ; CHECK-LABEL: @same_signbit_use3_signed(
 ; CHECK-NEXT:    [[XSIGN:%.*]] = ashr i8 [[X:%.*]], 7
@@ -1548,10 +1545,8 @@ define i1 @same_signbit_use3_signed(i8 %x, i8 %y) {
 
 define <2 x i1> @same_signbit_poison_elts_signed(<2 x i8> %x, <2 x i8> %y) {
 ; CHECK-LABEL: @same_signbit_poison_elts_signed(
-; CHECK-NEXT:    [[XSIGN:%.*]] = ashr <2 x i8> [[X:%.*]], <i8 7, i8 poison>
-; CHECK-NEXT:    [[YPOS:%.*]] = icmp sgt <2 x i8> [[Y:%.*]], <i8 -1, i8 poison>
-; CHECK-NEXT:    [[YPOSZ:%.*]] = sext <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 = ashr <2 x i8> %x, <i8 7, i8 poison>
@@ -1561,6 +1556,8 @@ define <2 x i1> @same_signbit_poison_elts_signed(<2 x i8> %x, <2 x i8> %y) {
   ret <2 x i1> %r
 }
 
+; negative test
+
 define i1 @same_signbit_wrong_type_signed(i8 %x, i32 %y) {
 ; CHECK-LABEL: @same_signbit_wrong_type_signed(
 ; CHECK-NEXT:    [[XSIGN:%.*]] = ashr i8 [[X:%.*]], 7
@@ -1576,6 +1573,8 @@ define i1 @same_signbit_wrong_type_signed(i8 %x, i32 %y) {
   ret i1 %r
 }
 
+; negative test
+
 define i1 @exactly_one_set_signbit_wrong_shamt_signed(i8 %x, i8 %y) {
 ; CHECK-LABEL: @exactly_one_set_signbit_wrong_shamt_signed(
 ; CHECK-NEXT:    [[XSIGN:%.*]] = ashr i8 [[X:%.*]], 6


        


More information about the llvm-commits mailing list