[InstCombine] Fold zero check followed by decrement to usub.sat
authorJamie Hill-Daniel <jamie@hill-daniel.co.uk>
Mon, 9 Jan 2023 13:21:12 +0000 (14:21 +0100)
committerNikita Popov <npopov@redhat.com>
Mon, 9 Jan 2023 13:22:25 +0000 (14:22 +0100)
Fold (a == 0) : 0 ? a - 1 into usub.sat(a, 1).

Differential Revision: https://reviews.llvm.org/D140798

llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
llvm/test/Transforms/InstCombine/saturating-add-sub.ll
llvm/test/Transforms/InstCombine/unsigned_saturated_sub.ll
llvm/test/Transforms/PhaseOrdering/pr44461-br-to-switch-rotate.ll

index 6fc7051..ea30c01 100644 (file)
@@ -803,19 +803,31 @@ static Value *canonicalizeSaturatedSubtract(const ICmpInst *ICI,
                                             const Value *FalseVal,
                                             InstCombiner::BuilderTy &Builder) {
   ICmpInst::Predicate Pred = ICI->getPredicate();
-  if (!ICmpInst::isUnsigned(Pred))
-    return nullptr;
+  Value *A = ICI->getOperand(0);
+  Value *B = ICI->getOperand(1);
 
   // (b > a) ? 0 : a - b -> (b <= a) ? a - b : 0
+  // (a == 0) ? 0 : a - 1 -> (a != 0) ? a - 1 : 0
   if (match(TrueVal, m_Zero())) {
     Pred = ICmpInst::getInversePredicate(Pred);
     std::swap(TrueVal, FalseVal);
   }
+
   if (!match(FalseVal, m_Zero()))
     return nullptr;
 
-  Value *A = ICI->getOperand(0);
-  Value *B = ICI->getOperand(1);
+  // ugt 0 is canonicalized to ne 0 and requires special handling
+  // (a != 0) ? a + -1 : 0 -> usub.sat(a, 1)
+  if (Pred == ICmpInst::ICMP_NE) {
+    if (match(B, m_Zero()) && match(TrueVal, m_Add(m_Specific(A), m_AllOnes())))
+      return Builder.CreateBinaryIntrinsic(Intrinsic::usub_sat, A,
+                                           ConstantInt::get(A->getType(), 1));
+    return nullptr;
+  }
+
+  if (!ICmpInst::isUnsigned(Pred))
+    return nullptr;
+
   if (Pred == ICmpInst::ICMP_ULE || Pred == ICmpInst::ICMP_ULT) {
     // (b < a) ? a - b : 0 -> (a > b) ? a - b : 0
     std::swap(A, B);
index 8556feb..f1b7637 100644 (file)
@@ -523,9 +523,7 @@ define i8 @test_scalar_usub_combine(i8 %a) {
 ; Can simplify zero check followed by decrement
 define i8 @test_simplify_decrement(i8 %a) {
 ; CHECK-LABEL: @test_simplify_decrement(
-; CHECK-NEXT:    [[I:%.*]] = icmp eq i8 [[A:%.*]], 0
-; CHECK-NEXT:    [[I1:%.*]] = add i8 [[A]], -1
-; CHECK-NEXT:    [[I2:%.*]] = select i1 [[I]], i8 0, i8 [[I1]]
+; CHECK-NEXT:    [[I2:%.*]] = call i8 @llvm.usub.sat.i8(i8 [[A:%.*]], i8 1)
 ; CHECK-NEXT:    ret i8 [[I2]]
 ;
   %i = icmp eq i8 %a, 0
@@ -540,8 +538,7 @@ define i8 @test_simplify_decrement_ne(i8 %a) {
 ; CHECK-LABEL: @test_simplify_decrement_ne(
 ; CHECK-NEXT:    [[I:%.*]] = icmp ne i8 [[A:%.*]], 0
 ; CHECK-NEXT:    call void @use.i1(i1 [[I]])
-; CHECK-NEXT:    [[I1:%.*]] = add i8 [[A]], -1
-; CHECK-NEXT:    [[I2:%.*]] = select i1 [[I]], i8 [[I1]], i8 0
+; CHECK-NEXT:    [[I2:%.*]] = call i8 @llvm.usub.sat.i8(i8 [[A]], i8 1)
 ; CHECK-NEXT:    ret i8 [[I2]]
 ;
   %i = icmp ne i8 %a, 0
@@ -553,9 +550,7 @@ define i8 @test_simplify_decrement_ne(i8 %a) {
 
 define <2 x i8> @test_simplify_decrement_vec(<2 x i8> %a) {
 ; CHECK-LABEL: @test_simplify_decrement_vec(
-; CHECK-NEXT:    [[I:%.*]] = icmp eq <2 x i8> [[A:%.*]], zeroinitializer
-; CHECK-NEXT:    [[I1:%.*]] = add <2 x i8> [[A]], <i8 -1, i8 -1>
-; CHECK-NEXT:    [[I2:%.*]] = select <2 x i1> [[I]], <2 x i8> zeroinitializer, <2 x i8> [[I1]]
+; CHECK-NEXT:    [[I2:%.*]] = call <2 x i8> @llvm.usub.sat.v2i8(<2 x i8> [[A:%.*]], <2 x i8> <i8 1, i8 1>)
 ; CHECK-NEXT:    ret <2 x i8> [[I2]]
 ;
   %i = icmp eq <2 x i8> %a, <i8 0, i8 0>
@@ -566,9 +561,7 @@ define <2 x i8> @test_simplify_decrement_vec(<2 x i8> %a) {
 
 define <2 x i8> @test_simplify_decrement_vec_undef(<2 x i8> %a) {
 ; CHECK-LABEL: @test_simplify_decrement_vec_undef(
-; CHECK-NEXT:    [[I:%.*]] = icmp eq <2 x i8> [[A:%.*]], zeroinitializer
-; CHECK-NEXT:    [[I1:%.*]] = add <2 x i8> [[A]], <i8 -1, i8 -1>
-; CHECK-NEXT:    [[I2:%.*]] = select <2 x i1> [[I]], <2 x i8> <i8 0, i8 undef>, <2 x i8> [[I1]]
+; CHECK-NEXT:    [[I2:%.*]] = call <2 x i8> @llvm.usub.sat.v2i8(<2 x i8> [[A:%.*]], <2 x i8> <i8 1, i8 1>)
 ; CHECK-NEXT:    ret <2 x i8> [[I2]]
 ;
   %i = icmp eq <2 x i8> %a, <i8 0, i8 0>
index 2b440c0..75b3c0d 100644 (file)
@@ -265,9 +265,7 @@ define i32 @max_sub_ugt_c1(i32 %a) {
 
 define i32 @max_sub_ugt_c01(i32 %a) {
 ; CHECK-LABEL: @max_sub_ugt_c01(
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[A:%.*]], 0
-; CHECK-NEXT:    [[SUB:%.*]] = add i32 [[A]], -1
-; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i32 0, i32 [[SUB]]
+; CHECK-NEXT:    [[SEL:%.*]] = call i32 @llvm.usub.sat.i32(i32 [[A:%.*]], i32 1)
 ; CHECK-NEXT:    ret i32 [[SEL]]
 ;
   %cmp = icmp ugt i32 %a, 0
index a97f085..6b92b1f 100644 (file)
@@ -19,8 +19,7 @@ define i64 @test() {
 ; CHECK:       bb3.i.i:
 ; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i64 [[ITER1_SROA_5_0]], 0
 ; CHECK-NEXT:    [[TMP3]] = zext i1 [[TMP2]] to i8
-; CHECK-NEXT:    [[_5_0_I_I_I_I:%.*]] = add i64 [[ITER1_SROA_5_0]], -1
-; CHECK-NEXT:    [[SPEC_SELECT]] = select i1 [[TMP2]], i64 0, i64 [[_5_0_I_I_I_I]]
+; CHECK-NEXT:    [[SPEC_SELECT]] = tail call i64 @llvm.usub.sat.i64(i64 [[ITER1_SROA_5_0]], i64 1)
 ; CHECK-NEXT:    [[TMP4]] = add i64 [[COUNT_1]], [[ITER1_SROA_5_0]]
 ; CHECK-NEXT:    br label [[BB10]]
 ; CHECK:       bb12: