diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp index 6fe9693581853..63725e4ca8113 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp @@ -994,6 +994,12 @@ Instruction *InstCombinerImpl::foldAddWithConstant(BinaryOperator &Add) { } } + // umax(X, C) + -C --> usub.sat(X, C) + if (match(Op0, m_OneUse(m_UMax(m_Value(X), m_SpecificInt(-*C))))) + return replaceInstUsesWith( + Add, Builder.CreateBinaryIntrinsic( + Intrinsic::usub_sat, X, ConstantInt::get(Add.getType(), -*C))); + // Fold (add (zext (add X, -1)), 1) -> (zext X) if X is non-zero. // TODO: There's a general form for any constant on the outer add. if (C->isOne()) { diff --git a/llvm/test/Transforms/InstCombine/saturating-add-sub.ll b/llvm/test/Transforms/InstCombine/saturating-add-sub.ll index 9236d96f59a55..d043f5b7ad116 100644 --- a/llvm/test/Transforms/InstCombine/saturating-add-sub.ll +++ b/llvm/test/Transforms/InstCombine/saturating-add-sub.ll @@ -2316,3 +2316,39 @@ define i32 @uadd_sat_via_add_swapped_cmp_select_nonstrict(i32 %x, i32 %y) { %r = select i1 %c, i32 %a, i32 -1 ret i32 %r } + +define i8 @fold_add_umax_to_usub(i8 %a) { +; CHECK-LABEL: @fold_add_umax_to_usub( +; CHECK-NEXT: [[SEL:%.*]] = call i8 @llvm.usub.sat.i8(i8 [[A:%.*]], i8 10) +; CHECK-NEXT: ret i8 [[SEL]] +; + %umax = call i8 @llvm.umax.i8(i8 %a, i8 10) + %sel = add i8 %umax, -10 + ret i8 %sel +} + +define i8 @fold_add_umax_to_usub_incorrect_rhs(i8 %a) { +; CHECK-LABEL: @fold_add_umax_to_usub_incorrect_rhs( +; CHECK-NEXT: [[UMAX:%.*]] = call i8 @llvm.umax.i8(i8 [[A:%.*]], i8 10) +; CHECK-NEXT: [[SEL:%.*]] = add i8 [[UMAX]], -11 +; CHECK-NEXT: ret i8 [[SEL]] +; + %umax = call i8 @llvm.umax.i8(i8 %a, i8 10) + %sel = add i8 %umax, -11 + ret i8 %sel +} + +define i8 @fold_add_umax_to_usub_multiuse(i8 %a) { +; CHECK-LABEL: @fold_add_umax_to_usub_multiuse( +; CHECK-NEXT: [[UMAX:%.*]] = call i8 @llvm.umax.i8(i8 [[A:%.*]], i8 10) +; CHECK-NEXT: call void @usei8(i8 [[UMAX]]) +; CHECK-NEXT: [[SEL:%.*]] = add i8 [[UMAX]], -10 +; CHECK-NEXT: ret i8 [[SEL]] +; + %umax = call i8 @llvm.umax.i8(i8 %a, i8 10) + call void @usei8(i8 %umax) + %sel = add i8 %umax, -10 + ret i8 %sel +} + +declare void @usei8(i8)