diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp @@ -803,19 +803,31 @@ 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); diff --git a/llvm/test/Transforms/InstCombine/saturating-add-sub.ll b/llvm/test/Transforms/InstCombine/saturating-add-sub.ll --- a/llvm/test/Transforms/InstCombine/saturating-add-sub.ll +++ b/llvm/test/Transforms/InstCombine/saturating-add-sub.ll @@ -523,9 +523,7 @@ ; 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 @@ ; 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 <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]], -; 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> ) ; CHECK-NEXT: ret <2 x i8> [[I2]] ; %i = icmp eq <2 x i8> %a, @@ -566,9 +561,7 @@ 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]], -; CHECK-NEXT: [[I2:%.*]] = select <2 x i1> [[I]], <2 x i8> , <2 x i8> [[I1]] +; CHECK-NEXT: [[I2:%.*]] = call <2 x i8> @llvm.usub.sat.v2i8(<2 x i8> [[A:%.*]], <2 x i8> ) ; CHECK-NEXT: ret <2 x i8> [[I2]] ; %i = icmp eq <2 x i8> %a, diff --git a/llvm/test/Transforms/InstCombine/unsigned_saturated_sub.ll b/llvm/test/Transforms/InstCombine/unsigned_saturated_sub.ll --- a/llvm/test/Transforms/InstCombine/unsigned_saturated_sub.ll +++ b/llvm/test/Transforms/InstCombine/unsigned_saturated_sub.ll @@ -265,9 +265,7 @@ 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 diff --git a/llvm/test/Transforms/PhaseOrdering/pr44461-br-to-switch-rotate.ll b/llvm/test/Transforms/PhaseOrdering/pr44461-br-to-switch-rotate.ll --- a/llvm/test/Transforms/PhaseOrdering/pr44461-br-to-switch-rotate.ll +++ b/llvm/test/Transforms/PhaseOrdering/pr44461-br-to-switch-rotate.ll @@ -19,8 +19,7 @@ ; 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: