[InstCombine] enhance icmp with sub folds
authorSanjay Patel <spatel@rotateright.com>
Sat, 9 Oct 2021 15:34:48 +0000 (11:34 -0400)
committerSanjay Patel <spatel@rotateright.com>
Sat, 9 Oct 2021 15:39:49 +0000 (11:39 -0400)
There were 2 related but over-specified folds for:
C1 - X == C

One allowed multi-use but was limited to equal constants.
The other allowed different constants but disallowed multi-use.

This combines the 2 folds into a more general match.
The test diffs show the multi-use cases that were falling
through the cracks.

https://alive2.llvm.org/ce/z/4_hEt2

  define i1 @src(i8 %x, i8 %subC, i8 %C) {
    %s = sub i8 %subC, %x
    %r = icmp eq i8 %s, %C
    ret i1 %r
  }

  define i1 @tgt(i8 %x, i8 %subC, i8 %C) {
    %newC = sub i8 %subC, %C
    %isneg = icmp eq i8 %x, %newC
    ret i1 %isneg
  }

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

index 03044ac..e080e7f 100644 (file)
@@ -2579,21 +2579,25 @@ Instruction *InstCombinerImpl::foldICmpSubConstant(ICmpInst &Cmp,
                                                    const APInt &C) {
   Value *X = Sub->getOperand(0), *Y = Sub->getOperand(1);
   ICmpInst::Predicate Pred = Cmp.getPredicate();
-  const APInt *C2;
-  APInt SubResult;
+  Type *Ty = Sub->getType();
 
-  // icmp eq/ne (sub C, Y), C -> icmp eq/ne Y, 0
-  if (match(X, m_APInt(C2)) && *C2 == C && Cmp.isEquality())
-    return new ICmpInst(Cmp.getPredicate(), Y,
-                        ConstantInt::get(Y->getType(), 0));
+  // (SubC - Y) == C) --> Y == (SubC - C)
+  // (SubC - Y) != C) --> Y != (SubC - C)
+  Constant *SubC;
+  if (Cmp.isEquality() && match(X, m_ImmConstant(SubC))) {
+    return new ICmpInst(Pred, Y,
+                        ConstantExpr::getSub(SubC, ConstantInt::get(Ty, C)));
+  }
 
   // (icmp P (sub nuw|nsw C2, Y), C) -> (icmp swap(P) Y, C2-C)
+  const APInt *C2;
+  APInt SubResult;
   if (match(X, m_APInt(C2)) &&
       ((Cmp.isUnsigned() && Sub->hasNoUnsignedWrap()) ||
        (Cmp.isSigned() && Sub->hasNoSignedWrap())) &&
       !subWithOverflow(SubResult, *C2, C, Cmp.isSigned()))
     return new ICmpInst(Cmp.getSwappedPredicate(), Y,
-                        ConstantInt::get(Y->getType(), SubResult));
+                        ConstantInt::get(Ty, SubResult));
 
   // The following transforms are only worth it if the only user of the subtract
   // is the icmp.
@@ -3122,12 +3126,7 @@ Instruction *InstCombinerImpl::foldICmpBinOpEqualityWithConstant(
     break;
   case Instruction::Sub:
     if (BO->hasOneUse()) {
-      // Only check for constant LHS here, as constant RHS will be canonicalized
-      // to add and use the fold above.
-      if (Constant *BOC = dyn_cast<Constant>(BOp0)) {
-        // Replace ((sub BOC, B) != C) with (B != BOC-C).
-        return new ICmpInst(Pred, BOp1, ConstantExpr::getSub(BOC, RHS));
-      } else if (C.isZero()) {
+      if (C.isZero()) {
         // Replace ((sub A, B) != 0) with (A != B).
         return new ICmpInst(Pred, BOp0, BOp1);
       }
index 4fa31be..0b62df6 100644 (file)
@@ -204,7 +204,7 @@ define i1 @neg_eq_43(i32 %x) {
 ; CHECK-LABEL: @neg_eq_43(
 ; CHECK-NEXT:    [[NEGX:%.*]] = sub i32 0, [[X:%.*]]
 ; CHECK-NEXT:    call void @use(i32 [[NEGX]])
-; CHECK-NEXT:    [[R:%.*]] = icmp eq i32 [[NEGX]], 43
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i32 [[X]], -43
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %negx = sub i32 0, %x
@@ -217,7 +217,7 @@ define i1 @neg_ne_44(i32 %x) {
 ; CHECK-LABEL: @neg_ne_44(
 ; CHECK-NEXT:    [[NEGX:%.*]] = sub i32 0, [[X:%.*]]
 ; CHECK-NEXT:    call void @use(i32 [[NEGX]])
-; CHECK-NEXT:    [[R:%.*]] = icmp ne i32 [[NEGX]], 44
+; CHECK-NEXT:    [[R:%.*]] = icmp ne i32 [[X]], -44
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %negx = sub i32 0, %x
@@ -230,7 +230,7 @@ define i1 @neg_nsw_eq_45(i32 %x) {
 ; CHECK-LABEL: @neg_nsw_eq_45(
 ; CHECK-NEXT:    [[NEGX:%.*]] = sub nsw i32 0, [[X:%.*]]
 ; CHECK-NEXT:    call void @use(i32 [[NEGX]])
-; CHECK-NEXT:    [[R:%.*]] = icmp eq i32 [[NEGX]], 45
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i32 [[X]], -45
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %negx = sub nsw i32 0, %x
@@ -243,7 +243,7 @@ define i1 @neg_nsw_ne_46(i32 %x) {
 ; CHECK-LABEL: @neg_nsw_ne_46(
 ; CHECK-NEXT:    [[NEGX:%.*]] = sub nsw i32 0, [[X:%.*]]
 ; CHECK-NEXT:    call void @use(i32 [[NEGX]])
-; CHECK-NEXT:    [[R:%.*]] = icmp ne i32 [[NEGX]], 46
+; CHECK-NEXT:    [[R:%.*]] = icmp ne i32 [[X]], -46
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %negx = sub nsw i32 0, %x
@@ -256,7 +256,7 @@ define i1 @subC_eq(i32 %x) {
 ; CHECK-LABEL: @subC_eq(
 ; CHECK-NEXT:    [[SUBX:%.*]] = sub i32 -2147483648, [[X:%.*]]
 ; CHECK-NEXT:    call void @use(i32 [[SUBX]])
-; CHECK-NEXT:    [[R:%.*]] = icmp eq i32 [[SUBX]], 43
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i32 [[X]], 2147483605
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %subx = sub i32 -2147483648, %x
@@ -269,7 +269,7 @@ define <2 x i1> @subC_ne(<2 x i8> %x) {
 ; CHECK-LABEL: @subC_ne(
 ; CHECK-NEXT:    [[SUBX:%.*]] = sub <2 x i8> <i8 -6, i8 -128>, [[X:%.*]]
 ; CHECK-NEXT:    call void @use_vec(<2 x i8> [[SUBX]])
-; CHECK-NEXT:    [[R:%.*]] = icmp ne <2 x i8> [[SUBX]], <i8 -44, i8 -44>
+; CHECK-NEXT:    [[R:%.*]] = icmp ne <2 x i8> [[X]], <i8 38, i8 -84>
 ; CHECK-NEXT:    ret <2 x i1> [[R]]
 ;
   %subx = sub <2 x i8> <i8 -6, i8 -128>, %x
@@ -282,7 +282,7 @@ define i1 @subC_nsw_eq(i32 %x) {
 ; CHECK-LABEL: @subC_nsw_eq(
 ; CHECK-NEXT:    [[SUBX:%.*]] = sub nsw i32 -100, [[X:%.*]]
 ; CHECK-NEXT:    call void @use(i32 [[SUBX]])
-; CHECK-NEXT:    [[R:%.*]] = icmp eq i32 [[SUBX]], -2147483648
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i32 [[X]], 2147483548
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %subx = sub nsw i32 -100, %x
@@ -295,7 +295,7 @@ define i1 @subC_nsw_ne(i32 %x) {
 ; CHECK-LABEL: @subC_nsw_ne(
 ; CHECK-NEXT:    [[SUBX:%.*]] = sub nsw i32 -2147483647, [[X:%.*]]
 ; CHECK-NEXT:    call void @use(i32 [[SUBX]])
-; CHECK-NEXT:    [[R:%.*]] = icmp ne i32 [[SUBX]], 46
+; CHECK-NEXT:    [[R:%.*]] = icmp ne i32 [[X]], 2147483603
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %subx = sub nsw i32 -2147483647, %x