Index: llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp @@ -803,6 +803,32 @@ const Value *FalseVal, InstCombiner::BuilderTy &Builder) { ICmpInst::Predicate Pred = ICI->getPredicate(); + // (a == 0) : 0 : a - 1 -> usub.sat(a, 1) + if (Pred == ICmpInst::ICMP_EQ) { + Value *A = ICI->getOperand(0); + Value *B = ICI->getOperand(1); + + if (!match(B, m_Zero())) + return nullptr; + + if (match(FalseVal, m_Zero())) { + if (Pred == ICmpInst::ICMP_NE) { + Pred = ICmpInst::getSwappedPredicate(Pred); + std::swap(TrueVal, FalseVal); + } + } + + if (!match(TrueVal, m_Zero())) + return nullptr; + + Value *One = ConstantInt::get(A->getType(), 1); + APInt APOne = cast(One)->getValue(); + if (match(FalseVal, m_Add(m_Specific(A), m_SpecificInt(-APOne)))) { + return Builder.CreateBinaryIntrinsic(Intrinsic::usub_sat, A, One); + } + return nullptr; + } + if (!ICmpInst::isUnsigned(Pred)) return nullptr; Index: llvm/test/Transforms/InstCombine/saturating-add-sub.ll =================================================================== --- llvm/test/Transforms/InstCombine/saturating-add-sub.ll +++ llvm/test/Transforms/InstCombine/saturating-add-sub.ll @@ -520,6 +520,91 @@ ret i8 %x2 } +; Can simplify zero check followed by decrement +define i8 @test_simplify_decrement(i8 %a) { +; CHECK-LABEL: @test_simplify_decrement( +; CHECK-NEXT: [[I2:%.*]] = call i8 @llvm.usub.sat.i8(i8 [[A:%.*]], i8 1) +; CHECK-NEXT: ret i8 [[I2]] +; + %i = icmp eq i8 %a, 0 + %i1 = sub i8 %a, 1 + %i2 = select i1 %i, i8 0, i8 %i1 + ret i8 %i2 +} + +define i8 @test_simplify_decrement_ne(i8 %a) { +; CHECK-LABEL: @test_simplify_decrement_ne( +; CHECK-NEXT: [[I2:%.*]] = call i8 @llvm.usub.sat.i8(i8 [[A:%.*]], i8 1) +; CHECK-NEXT: ret i8 [[I2]] +; + %i = icmp ne i8 %a, 0 + %i1 = sub i8 %a, 1 + %i2 = select i1 %i, i8 %i1, i8 0 + ret i8 %i2 +} + +define i8 @test_simplify_decrement_invalid_ne(i8 %a) { +; CHECK-LABEL: @test_simplify_decrement_invalid_ne( +; CHECK-NEXT: [[I_NOT:%.*]] = icmp eq i8 [[A:%.*]], 0 +; CHECK-NEXT: [[I2:%.*]] = sext i1 [[I_NOT]] to i8 +; CHECK-NEXT: ret i8 [[I2]] +; + %i = icmp ne i8 %a, 0 + %i1 = sub i8 %a, 1 + %i2 = select i1 %i, i8 0, i8 %i1 + ret i8 %i2 +} + +define i8 @test_invalid_simplify_sub2(i8 %a) { +; CHECK-LABEL: @test_invalid_simplify_sub2( +; CHECK-NEXT: [[I:%.*]] = icmp eq i8 [[A:%.*]], 0 +; CHECK-NEXT: [[I1:%.*]] = add i8 [[A]], -2 +; CHECK-NEXT: [[I2:%.*]] = select i1 [[I]], i8 0, i8 [[I1]] +; CHECK-NEXT: ret i8 [[I2]] +; + %i = icmp eq i8 %a, 0 + %i1 = sub i8 %a, 2 + %i2 = select i1 %i, i8 0, i8 %i1 + ret i8 %i2 +} + +define i8 @test_invalid_simplify_eq1(i8 %a) { +; CHECK-LABEL: @test_invalid_simplify_eq1( +; CHECK-NEXT: [[I1:%.*]] = add i8 [[A:%.*]], -1 +; CHECK-NEXT: ret i8 [[I1]] +; + %i = icmp eq i8 %a, 1 + %i1 = sub i8 %a, 1 + %i2 = select i1 %i, i8 0, i8 %i1 + ret i8 %i2 +} + +define i8 @test_invalid_simplify_select_1(i8 %a) { +; CHECK-LABEL: @test_invalid_simplify_select_1( +; CHECK-NEXT: [[I:%.*]] = icmp eq i8 [[A:%.*]], 0 +; CHECK-NEXT: [[I1:%.*]] = add i8 [[A]], -1 +; CHECK-NEXT: [[I2:%.*]] = select i1 [[I]], i8 1, i8 [[I1]] +; CHECK-NEXT: ret i8 [[I2]] +; + %i = icmp eq i8 %a, 0 + %i1 = sub i8 %a, 1 + %i2 = select i1 %i, i8 1, i8 %i1 + ret i8 %i2 +} + +define i8 @test_invalid_simplify_other(i8 %a, i8 %b) { +; CHECK-LABEL: @test_invalid_simplify_other( +; CHECK-NEXT: [[I:%.*]] = icmp eq i8 [[A:%.*]], 1 +; CHECK-NEXT: [[I1:%.*]] = add i8 [[B:%.*]], -1 +; CHECK-NEXT: [[I2:%.*]] = select i1 [[I]], i8 0, i8 [[I1]] +; CHECK-NEXT: ret i8 [[I2]] +; + %i = icmp eq i8 %a, 1 + %i1 = sub i8 %b, 1 + %i2 = select i1 %i, i8 0, i8 %i1 + ret i8 %i2 +} + define <2 x i8> @test_vector_usub_combine(<2 x i8> %a) { ; CHECK-LABEL: @test_vector_usub_combine( ; CHECK-NEXT: [[TMP1:%.*]] = call <2 x i8> @llvm.usub.sat.v2i8(<2 x i8> [[A:%.*]], <2 x i8> )