[InstCombine] reduce signbit test of logic ops to cmp with zero
authorSanjay Patel <spatel@rotateright.com>
Mon, 12 Jul 2021 12:58:05 +0000 (08:58 -0400)
committerSanjay Patel <spatel@rotateright.com>
Mon, 12 Jul 2021 13:01:26 +0000 (09:01 -0400)
This is the pattern from the description of:
https://llvm.org/PR50816

There might be a way to generalize this to a smaller or more
generic pattern, but I have not found it yet.

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

define i1 @src(i8 %x) {
  %add = add i8 %x, -1
  %xor = xor i8 %x, -1
  %and = and i8 %add, %xor
  %r = icmp slt i8 %and, 0
  ret i1 %r
}

define i1 @tgt(i8 %x) {
  %r = icmp eq i8 %x, 0
  ret i1 %r
}

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

index 6e66c61..031b95e 100644 (file)
@@ -1855,6 +1855,19 @@ Instruction *InstCombinerImpl::foldICmpAndConstant(ICmpInst &Cmp,
   if (Instruction *I = foldICmpAndConstConst(Cmp, And, C))
     return I;
 
+  const ICmpInst::Predicate Pred = Cmp.getPredicate();
+  bool TrueIfNeg;
+  if (isSignBitCheck(Pred, C, TrueIfNeg)) {
+    // ((X - 1) & ~X) <  0 --> X == 0
+    // ((X - 1) & ~X) >= 0 --> X != 0
+    Value *X;
+    if (match(And->getOperand(0), m_Add(m_Value(X), m_AllOnes())) &&
+        match(And->getOperand(1), m_Not(m_Specific(X)))) {
+      auto NewPred = TrueIfNeg ? CmpInst::ICMP_EQ : CmpInst::ICMP_NE;
+      return new ICmpInst(NewPred, X, ConstantInt::getNullValue(X->getType()));
+    }
+  }
+
   // TODO: These all require that Y is constant too, so refactor with the above.
 
   // Try to optimize things like "A[i] & 42 == 0" to index computations.
@@ -1877,8 +1890,8 @@ Instruction *InstCombinerImpl::foldICmpAndConstant(ICmpInst &Cmp,
   // X & -C != -C -> X <= u ~C
   //   iff C is a power of 2
   if (Cmp.getOperand(1) == Y && (-C).isPowerOf2()) {
-    auto NewPred = Cmp.getPredicate() == CmpInst::ICMP_EQ ? CmpInst::ICMP_UGT
-                                                          : CmpInst::ICMP_ULE;
+    auto NewPred =
+        Pred == CmpInst::ICMP_EQ ? CmpInst::ICMP_UGT : CmpInst::ICMP_ULE;
     return new ICmpInst(NewPred, X, SubOne(cast<Constant>(Cmp.getOperand(1))));
   }
 
@@ -1893,8 +1906,8 @@ Instruction *InstCombinerImpl::foldICmpAndConstant(ICmpInst &Cmp,
       if (auto *AndVTy = dyn_cast<VectorType>(And->getType()))
         NTy = VectorType::get(NTy, AndVTy->getElementCount());
       Value *Trunc = Builder.CreateTrunc(X, NTy);
-      auto NewPred = Cmp.getPredicate() == CmpInst::ICMP_EQ ? CmpInst::ICMP_SGE
-                                                            : CmpInst::ICMP_SLT;
+      auto NewPred =
+          Pred == CmpInst::ICMP_EQ ? CmpInst::ICMP_SGE : CmpInst::ICMP_SLT;
       return new ICmpInst(NewPred, Trunc, Constant::getNullValue(NTy));
     }
   }
index 30b6c88..3d254ef 100644 (file)
@@ -3953,10 +3953,7 @@ define i1 @thread_cmp_over_select_with_poison_falseval(i1 %b) {
 
 define i1 @signbit_true_logic(i8 %x) {
 ; CHECK-LABEL: @signbit_true_logic(
-; CHECK-NEXT:    [[DEC:%.*]] = add i8 [[X:%.*]], -1
-; CHECK-NEXT:    [[NOT:%.*]] = xor i8 [[X]], -1
-; CHECK-NEXT:    [[AND:%.*]] = and i8 [[DEC]], [[NOT]]
-; CHECK-NEXT:    [[R:%.*]] = icmp slt i8 [[AND]], 0
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i8 [[X:%.*]], 0
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %dec = add i8 %x, -1
@@ -3968,10 +3965,7 @@ define i1 @signbit_true_logic(i8 %x) {
 
 define <2 x i1> @signbit_false_logic(<2 x i5> %x) {
 ; CHECK-LABEL: @signbit_false_logic(
-; CHECK-NEXT:    [[DEC:%.*]] = add <2 x i5> [[X:%.*]], <i5 -1, i5 undef>
-; CHECK-NEXT:    [[NOT:%.*]] = xor <2 x i5> [[X]], <i5 -1, i5 -1>
-; CHECK-NEXT:    [[AND:%.*]] = and <2 x i5> [[DEC]], [[NOT]]
-; CHECK-NEXT:    [[R:%.*]] = icmp sgt <2 x i5> [[AND]], <i5 -1, i5 -1>
+; CHECK-NEXT:    [[R:%.*]] = icmp ne <2 x i5> [[X:%.*]], zeroinitializer
 ; CHECK-NEXT:    ret <2 x i1> [[R]]
 ;
   %dec = add <2 x i5> %x,  <i5 -1, i5 undef>
@@ -3991,7 +3985,7 @@ define i1 @signbit_true_logic_uses_commute(i64 %x) {
 ; CHECK-NEXT:    call void @use_i64(i64 [[NOT]])
 ; CHECK-NEXT:    [[AND:%.*]] = and i64 [[DEC]], [[NOT]]
 ; CHECK-NEXT:    call void @use_i64(i64 [[AND]])
-; CHECK-NEXT:    [[R:%.*]] = icmp slt i64 [[AND]], 0
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i64 [[X]], 0
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %dec = add i64 %x, -1