Index: llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp @@ -704,16 +704,24 @@ 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 sub is used anywhere else, we wouldn't be able to eliminate it - // afterwards. - if (!TrueVal->hasOneUse()) + // If we are adding a negate and the sub and icmp are used anywhere else, we + // would end up with more instructions. + if (IsNegative && !TrueVal->hasOneUse() && !ICI->hasOneUse()) return nullptr; // (a > b) ? a - b : 0 -> usub.sat(a, b) Index: llvm/test/Transforms/InstCombine/builtin-dynamic-object-size.ll =================================================================== --- llvm/test/Transforms/InstCombine/builtin-dynamic-object-size.ll +++ 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() { Index: llvm/test/Transforms/InstCombine/unsigned_saturated_sub.ll =================================================================== --- llvm/test/Transforms/InstCombine/unsigned_saturated_sub.ll +++ llvm/test/Transforms/InstCombine/unsigned_saturated_sub.ll @@ -36,11 +36,10 @@ define i64 @max_sub_uge_extrause1(i64 %a, i64 %b) { ; CHECK-LABEL: @max_sub_uge_extrause1( -; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[A:%.*]], [[B:%.*]] -; CHECK-NEXT: [[SUB:%.*]] = sub i64 [[A]], [[B]] -; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i64 0, i64 [[SUB]] +; CHECK-NEXT: [[SUB:%.*]] = sub i64 [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[TMP1:%.*]] = call i64 @llvm.usub.sat.i64(i64 [[A]], i64 [[B]]) ; CHECK-NEXT: call void @use(i64 [[SUB]]) -; CHECK-NEXT: ret i64 [[SEL]] +; CHECK-NEXT: ret i64 [[TMP1]] ; %cmp = icmp uge i64 %a, %b %sub = sub i64 %a, %b @@ -67,10 +66,10 @@ ; CHECK-LABEL: @max_sub_uge_extrause3( ; CHECK-NEXT: [[CMP:%.*]] = icmp uge i64 [[A:%.*]], [[B:%.*]] ; CHECK-NEXT: [[SUB:%.*]] = sub i64 [[A]], [[B]] -; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i64 [[SUB]], i64 0 +; CHECK-NEXT: [[TMP1:%.*]] = call i64 @llvm.usub.sat.i64(i64 [[A]], i64 [[B]]) ; CHECK-NEXT: call void @use(i64 [[SUB]]) ; CHECK-NEXT: call void @usei1(i1 [[CMP]]) -; CHECK-NEXT: ret i64 [[SEL]] +; CHECK-NEXT: ret i64 [[TMP1]] ; %cmp = icmp uge i64 %a, %b %sub = sub i64 %a, %b @@ -205,11 +204,11 @@ define i64 @neg_max_sub_ugt_sel_swapped_extrause2(i64 %a, i64 %b) { ; CHECK-LABEL: @neg_max_sub_ugt_sel_swapped_extrause2( -; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i64 [[B:%.*]], [[A:%.*]] -; CHECK-NEXT: [[SUB:%.*]] = sub i64 [[B]], [[A]] -; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i64 0, i64 [[SUB]] +; CHECK-NEXT: [[SUB:%.*]] = sub i64 [[B:%.*]], [[A:%.*]] +; CHECK-NEXT: [[TMP1:%.*]] = call i64 @llvm.usub.sat.i64(i64 [[A]], i64 [[B]]) +; CHECK-NEXT: [[TMP2:%.*]] = sub i64 0, [[TMP1]] ; CHECK-NEXT: call void @use(i64 [[SUB]]) -; CHECK-NEXT: ret i64 [[SEL]] +; CHECK-NEXT: ret i64 [[TMP2]] ; %cmp = icmp ugt i64 %b, %a %sub = sub i64 %b, %a @@ -255,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 @@ -281,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 @@ -355,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 @@ -369,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 @@ -383,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