[InstCombine] reduce compare of signbits of 2 values, signed variant
authorSanjay Patel <spatel@rotateright.com>
Wed, 25 Jan 2023 21:27:29 +0000 (16:27 -0500)
committerSanjay Patel <spatel@rotateright.com>
Thu, 26 Jan 2023 13:58:45 +0000 (08:58 -0500)
(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

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

index 1480a0f..8e90014 100644 (file)
@@ -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 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
+  // 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
+  // (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);
+      }
     }
   }
 
index 0259e60..f4dfa2e 100644 (file)
@@ -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