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 @@ -704,11 +704,19 @@ assert((Pred == ICmpInst::ICMP_UGE || Pred == ICmpInst::ICMP_UGT) && "Unexpected isUnsigned predicate!"); - // Account for swapped form of subtraction: ((a > b) ? b - a : 0). + // Ensure the sub is of the form: + // (a > b) ? a - b : 0 -> usub.sat(a, b) + // (a > b) ? b - a : 0 -> -usub.sat(a, b) + // Checking for both a-b and a+(-b) as a constant. bool IsNegative = false; - if (match(TrueVal, m_Sub(m_Specific(B), m_Specific(A)))) + const APInt *C; + if (match(TrueVal, m_Sub(m_Specific(B), m_Specific(A))) || + (match(A, m_APInt(C)) && + match(TrueVal, m_Add(m_Specific(B), m_SpecificInt(-*C))))) IsNegative = true; - else if (!match(TrueVal, m_Sub(m_Specific(A), m_Specific(B)))) + else if (!match(TrueVal, m_Sub(m_Specific(A), m_Specific(B))) && + !(match(B, m_APInt(C)) && + match(TrueVal, m_Add(m_Specific(A), m_SpecificInt(-*C))))) return nullptr; // If we are adding a negate and the sub and icmp are used anywhere else, we diff --git a/llvm/test/Transforms/InstCombine/builtin-dynamic-object-size.ll b/llvm/test/Transforms/InstCombine/builtin-dynamic-object-size.ll --- a/llvm/test/Transforms/InstCombine/builtin-dynamic-object-size.ll +++ b/llvm/test/Transforms/InstCombine/builtin-dynamic-object-size.ll @@ -48,10 +48,8 @@ ; CHECK: define i64 @internal_pointer(i64 %sz) ; CHECK-NEXT: entry: -; CHECK-NEXT: %0 = add i64 %sz, -2 -; CHECK-NEXT: %1 = icmp ult i64 %sz, 2 -; CHECK-NEXT: %2 = select i1 %1, i64 0, i64 %0 -; CHECK-NEXT: ret i64 %2 +; CHECK-NEXT: %0 = call i64 @llvm.usub.sat.i64(i64 %sz, i64 2) +; CHECK-NEXT: ret i64 %0 ; CHECK-NEXT: } define i64 @uses_nullptr_no_fold() { 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 @@ -254,10 +254,8 @@ define i32 @max_sub_ugt_c1(i32 %a) { ; CHECK-LABEL: @max_sub_ugt_c1( -; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i32 [[A:%.*]], 1 -; CHECK-NEXT: [[SUB:%.*]] = add i32 [[A]], -1 -; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i32 [[SUB]], i32 0 -; CHECK-NEXT: ret i32 [[SEL]] +; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.usub.sat.i32(i32 [[A:%.*]], i32 1) +; CHECK-NEXT: ret i32 [[TMP1]] ; %cmp = icmp ugt i32 %a, 1 %sub = add i32 %a, -1 @@ -280,10 +278,8 @@ define i32 @max_sub_ugt_c10(i32 %a) { ; CHECK-LABEL: @max_sub_ugt_c10( -; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i32 [[A:%.*]], 10 -; CHECK-NEXT: [[SUB:%.*]] = add i32 [[A]], -10 -; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i32 [[SUB]], i32 0 -; CHECK-NEXT: ret i32 [[SEL]] +; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.usub.sat.i32(i32 [[A:%.*]], i32 10) +; CHECK-NEXT: ret i32 [[TMP1]] ; %cmp = icmp ugt i32 %a, 10 %sub = add i32 %a, -10 @@ -354,10 +350,9 @@ define i32 @max_sub_ult_c2(i32 %a) { ; CHECK-LABEL: @max_sub_ult_c2( -; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[A:%.*]], 2 -; CHECK-NEXT: [[SUB:%.*]] = add i32 [[A]], -2 -; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i32 [[SUB]], i32 0 -; CHECK-NEXT: ret i32 [[SEL]] +; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.usub.sat.i32(i32 2, i32 [[A:%.*]]) +; CHECK-NEXT: [[TMP2:%.*]] = sub nsw i32 0, [[TMP1]] +; CHECK-NEXT: ret i32 [[TMP2]] ; %cmp = icmp ult i32 %a, 2 %sub = add i32 %a, -2 @@ -368,10 +363,10 @@ define i32 @max_sub_ult_c2_oneuseicmp(i32 %a) { ; CHECK-LABEL: @max_sub_ult_c2_oneuseicmp( ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[A:%.*]], 2 -; CHECK-NEXT: [[SUB:%.*]] = add i32 [[A]], -2 -; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i32 [[SUB]], i32 0 +; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.usub.sat.i32(i32 2, i32 [[A]]) +; CHECK-NEXT: [[TMP2:%.*]] = sub nsw i32 0, [[TMP1]] ; CHECK-NEXT: call void @usei1(i1 [[CMP]]) -; CHECK-NEXT: ret i32 [[SEL]] +; CHECK-NEXT: ret i32 [[TMP2]] ; %cmp = icmp ult i32 %a, 2 %sub = add i32 %a, -2 @@ -382,11 +377,11 @@ define i32 @max_sub_ult_c2_oneusesub(i32 %a) { ; CHECK-LABEL: @max_sub_ult_c2_oneusesub( -; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[A:%.*]], 2 -; CHECK-NEXT: [[SUB:%.*]] = add i32 [[A]], -2 -; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i32 [[SUB]], i32 0 +; CHECK-NEXT: [[SUB:%.*]] = add i32 [[A:%.*]], -2 +; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.usub.sat.i32(i32 2, i32 [[A]]) +; CHECK-NEXT: [[TMP2:%.*]] = sub nsw i32 0, [[TMP1]] ; CHECK-NEXT: call void @usei32(i32 [[SUB]]) -; CHECK-NEXT: ret i32 [[SEL]] +; CHECK-NEXT: ret i32 [[TMP2]] ; %cmp = icmp ult i32 %a, 2 %sub = add i32 %a, -2