[clang] [llvm] [InstCombine] Fold `X Pred C2 ? X BOp C1 : C2 BOp C1` to `min/max(X, C2) BOp C1` (PR #116888)

via cfe-commits cfe-commits at lists.llvm.org
Fri Nov 29 17:35:26 PST 2024


https://github.com/veera-sivarajan updated https://github.com/llvm/llvm-project/pull/116888

>From 77c2b799a067270ba23dde2cd3b7324c9c26b362 Mon Sep 17 00:00:00 2001
From: Veera <sveera.2001 at gmail.com>
Date: Thu, 28 Nov 2024 18:07:30 +0000
Subject: [PATCH 1/2] Add Test

---
 .../InstCombine/canonicalize-const-to-bop.ll  | 414 ++++++++++++++++++
 1 file changed, 414 insertions(+)
 create mode 100644 llvm/test/Transforms/InstCombine/canonicalize-const-to-bop.ll

diff --git a/llvm/test/Transforms/InstCombine/canonicalize-const-to-bop.ll b/llvm/test/Transforms/InstCombine/canonicalize-const-to-bop.ll
new file mode 100644
index 00000000000000..a23fc84aebd2e3
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/canonicalize-const-to-bop.ll
@@ -0,0 +1,414 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+define i8 @add_and_sgt(i8 %x) {
+; CHECK-LABEL: define i8 @add_and_sgt(
+; CHECK-SAME: i8 [[X:%.*]]) {
+; CHECK-NEXT:    [[ADD:%.*]] = add nsw i8 [[X]], 16
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 [[X]], 8
+; CHECK-NEXT:    [[S:%.*]] = select i1 [[CMP]], i8 [[ADD]], i8 24
+; CHECK-NEXT:    ret i8 [[S]]
+;
+  %add = add nsw i8 %x, 16
+  %cmp = icmp sgt i8 %x, 8
+  %s = select i1 %cmp, i8 %add, i8 24
+  ret i8 %s
+}
+
+define i8 @add_sgt_nuw(i8 %x) {
+; CHECK-LABEL: define i8 @add_sgt_nuw(
+; CHECK-SAME: i8 [[X:%.*]]) {
+; CHECK-NEXT:    [[ADD:%.*]] = add nuw i8 [[X]], 16
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 [[X]], 8
+; CHECK-NEXT:    [[S:%.*]] = select i1 [[CMP]], i8 [[ADD]], i8 24
+; CHECK-NEXT:    ret i8 [[S]]
+;
+  %add = add nuw i8 %x, 16
+  %cmp = icmp sgt i8 %x, 8
+  %s = select i1 %cmp, i8 %add, i8 24
+  ret i8 %s
+}
+
+define i8 @sub_and_ugt(i8 %x) {
+; CHECK-LABEL: define i8 @sub_and_ugt(
+; CHECK-SAME: i8 [[X:%.*]]) {
+; CHECK-NEXT:    [[SUB:%.*]] = add nsw i8 [[X]], -50
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i8 [[X]], 100
+; CHECK-NEXT:    [[S:%.*]] = select i1 [[CMP]], i8 50, i8 [[SUB]]
+; CHECK-NEXT:    ret i8 [[S]]
+;
+  %sub = sub nsw i8 %x, 50
+  %cmp = icmp ugt i8 %x, 100
+  %s = select i1 %cmp, i8 50, i8 %sub
+  ret i8 %s
+}
+
+define i8 @sub_ugt_nuw_nsw(i8 %x) {
+; CHECK-LABEL: define i8 @sub_ugt_nuw_nsw(
+; CHECK-SAME: i8 [[X:%.*]]) {
+; CHECK-NEXT:    [[SUB:%.*]] = add nsw i8 [[X]], -50
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i8 [[X]], 100
+; CHECK-NEXT:    [[S:%.*]] = select i1 [[CMP]], i8 50, i8 [[SUB]]
+; CHECK-NEXT:    ret i8 [[S]]
+;
+  %sub = sub nuw nsw i8 %x, 50
+  %cmp = icmp ugt i8 %x, 100
+  %s = select i1 %cmp, i8 50, i8 %sub
+  ret i8 %s
+}
+
+define i8 @mul_and_ult(i8 %x) {
+; CHECK-LABEL: define i8 @mul_and_ult(
+; CHECK-SAME: i8 [[X:%.*]]) {
+; CHECK-NEXT:    [[ADD:%.*]] = mul nsw i8 [[X]], 10
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i8 [[X]], 10
+; CHECK-NEXT:    [[S:%.*]] = select i1 [[CMP]], i8 100, i8 [[ADD]]
+; CHECK-NEXT:    ret i8 [[S]]
+;
+  %add = mul nsw i8 %x, 10
+  %cmp = icmp ult i8 10, %x
+  %s = select i1 %cmp, i8 100, i8 %add
+  ret i8 %s
+}
+
+define i8 @mul_and_non_strict_predicate(i8 %x) {
+; CHECK-LABEL: define i8 @mul_and_non_strict_predicate(
+; CHECK-SAME: i8 [[X:%.*]]) {
+; CHECK-NEXT:    [[ADD:%.*]] = mul nsw i8 [[X]], 10
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 [[X]], 9
+; CHECK-NEXT:    [[S:%.*]] = select i1 [[CMP]], i8 100, i8 [[ADD]]
+; CHECK-NEXT:    ret i8 [[S]]
+;
+  %add = mul nsw i8 %x, 10
+  %cmp = icmp sle i8 10, %x
+  %s = select i1 %cmp, i8 100, i8 %add
+  ret i8 %s
+}
+
+define i8 @mul_ult_noflags(i8 %x) {
+; CHECK-LABEL: define i8 @mul_ult_noflags(
+; CHECK-SAME: i8 [[X:%.*]]) {
+; CHECK-NEXT:    [[ADD:%.*]] = mul i8 [[X]], 10
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i8 [[X]], 10
+; CHECK-NEXT:    [[S:%.*]] = select i1 [[CMP]], i8 100, i8 [[ADD]]
+; CHECK-NEXT:    ret i8 [[S]]
+;
+  %add = mul i8 %x, 10
+  %cmp = icmp ult i8 10, %x
+  %s = select i1 %cmp, i8 100, i8 %add
+  ret i8 %s
+}
+
+define i8 @udiv_and_slt(i8 %x) {
+; CHECK-LABEL: define i8 @udiv_and_slt(
+; CHECK-SAME: i8 [[X:%.*]]) {
+; CHECK-NEXT:    [[SUB:%.*]] = udiv i8 [[X]], 10
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 [[X]], 100
+; CHECK-NEXT:    [[S:%.*]] = select i1 [[CMP]], i8 10, i8 [[SUB]]
+; CHECK-NEXT:    ret i8 [[S]]
+;
+  %sub = udiv i8 %x, 10
+  %cmp = icmp slt i8 %x, 100
+  %s = select i1 %cmp, i8 10, i8 %sub
+  ret i8 %s
+}
+
+define i8 @udiv_slt_exact(i8 %x) {
+; CHECK-LABEL: define i8 @udiv_slt_exact(
+; CHECK-SAME: i8 [[X:%.*]]) {
+; CHECK-NEXT:    [[SUB:%.*]] = udiv exact i8 [[X]], 10
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 [[X]], 100
+; CHECK-NEXT:    [[S:%.*]] = select i1 [[CMP]], i8 10, i8 [[SUB]]
+; CHECK-NEXT:    ret i8 [[S]]
+;
+  %sub = udiv exact i8 %x, 10
+  %cmp = icmp slt i8 %x, 100
+  %s = select i1 %cmp, i8 10, i8 %sub
+  ret i8 %s
+}
+
+define i8 @canonicalize_icmp_operands(i8 %x) {
+; CHECK-LABEL: define i8 @canonicalize_icmp_operands(
+; CHECK-SAME: i8 [[X:%.*]]) {
+; CHECK-NEXT:    [[ADD:%.*]] = add nsw i8 [[X]], 8
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 [[X]], 119
+; CHECK-NEXT:    [[S:%.*]] = select i1 [[CMP]], i8 127, i8 [[ADD]]
+; CHECK-NEXT:    ret i8 [[S]]
+;
+  %add = add nsw i8 %x, 8
+  %cmp = icmp sle i8 120, %x
+  %s = select i1 %cmp, i8 127, i8 %add
+  ret i8 %s
+}
+
+define i8 @flipped_strictness_predicate_and_constant(i8 %x, i8 %y) {
+; CHECK-LABEL: define i8 @flipped_strictness_predicate_and_constant(
+; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) {
+; CHECK-NEXT:    [[A:%.*]] = add i8 [[X]], -2
+; CHECK-NEXT:    [[C:%.*]] = icmp ult i8 [[X]], 2
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[C]], i8 -1, i8 [[A]]
+; CHECK-NEXT:    ret i8 [[R]]
+;
+  %a = add i8 %x, -2
+  %c = icmp ult i8 %x, 2
+  %r = select i1 %c, i8 -1, i8 %a
+  ret i8 %r
+}
+
+declare void @use(i1)
+declare void @use_byte(i8)
+
+define i8 @multi_use_cond_and_sel(i8 %x) {
+; CHECK-LABEL: define i8 @multi_use_cond_and_sel(
+; CHECK-SAME: i8 [[X:%.*]]) {
+; CHECK-NEXT:    [[ADD:%.*]] = add nsw i8 [[X]], 16
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 [[X]], 8
+; CHECK-NEXT:    call void @use(i1 [[CMP]])
+; CHECK-NEXT:    [[S:%.*]] = select i1 [[CMP]], i8 [[ADD]], i8 24
+; CHECK-NEXT:    call void @use_byte(i8 [[S]])
+; CHECK-NEXT:    ret i8 [[S]]
+;
+  %add = add nsw i8 %x, 16
+  %cmp = icmp sgt i8 %x, 8
+  call void @use(i1 %cmp)
+  %s = select i1 %cmp, i8 %add, i8 24
+  call void @use_byte(i8 %s)
+  ret i8 %s
+}
+
+define void @rust_noop_loop() {
+; CHECK-LABEL: define void @rust_noop_loop() {
+; CHECK-NEXT:  [[START:.*]]:
+; CHECK-NEXT:    br label %[[BB2_I:.*]]
+; CHECK:       [[BB2_I]]:
+; CHECK-NEXT:    [[ITER_SROA_0_07:%.*]] = phi i32 [ 0, %[[START]] ], [ [[SPEC_SELECT5:%.*]], %[[BB2_I]] ]
+; CHECK-NEXT:    [[_0_I3_I:%.*]] = icmp sgt i32 [[ITER_SROA_0_07]], 99
+; CHECK-NEXT:    [[TMP0:%.*]] = add nsw i32 [[ITER_SROA_0_07]], 1
+; CHECK-NEXT:    [[SPEC_SELECT5]] = select i1 [[_0_I3_I]], i32 100, i32 [[TMP0]]
+; CHECK-NEXT:    [[_0_I_NOT_I:%.*]] = icmp sgt i32 [[SPEC_SELECT5]], 100
+; CHECK-NEXT:    [[OR_COND:%.*]] = select i1 [[_0_I3_I]], i1 true, i1 [[_0_I_NOT_I]]
+; CHECK-NEXT:    br i1 [[OR_COND]], label %[[BASICBLOCK4:.*]], label %[[BB2_I]]
+; CHECK:       [[BASICBLOCK4]]:
+; CHECK-NEXT:    ret void
+;
+start:
+  br label %bb2.i
+
+bb2.i:
+  %iter.sroa.0.07 = phi i32 [ 0, %start ], [ %spec.select5, %bb2.i ]
+  %_0.i3.i = icmp sgt i32 %iter.sroa.0.07, 99
+  %0 = add nsw i32 %iter.sroa.0.07, 1
+  %spec.select5 = select i1 %_0.i3.i, i32 100, i32 %0
+  %_0.i.not.i = icmp sgt i32 %spec.select5, 100
+  %or.cond = select i1 %_0.i3.i, i1 true, i1 %_0.i.not.i
+  br i1 %or.cond, label %basicblock4, label %bb2.i
+
+basicblock4:
+  ret void
+}
+
+define <2 x i8> @add_non_splat_vector(<2 x i8> %x) {
+; CHECK-LABEL: define <2 x i8> @add_non_splat_vector(
+; CHECK-SAME: <2 x i8> [[X:%.*]]) {
+; CHECK-NEXT:    [[ADD:%.*]] = add <2 x i8> [[X]], <i8 1, i8 0>
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt <2 x i8> [[X]], <i8 0, i8 1>
+; CHECK-NEXT:    [[S:%.*]] = select <2 x i1> [[CMP]], <2 x i8> [[ADD]], <2 x i8> splat (i8 1)
+; CHECK-NEXT:    ret <2 x i8> [[S]]
+;
+  %add = add <2 x i8> %x, <i8 1, i8 0>
+  %cmp = icmp sgt <2 x i8> %x, <i8 0, i8 1>
+  %s = select <2 x i1> %cmp, <2 x i8> %add, <2 x i8> <i8 1, i8 1>
+  ret <2 x i8> %s
+}
+
+define <2 x i8> @or_splat_vector(<2 x i8> %x) {
+; CHECK-LABEL: define <2 x i8> @or_splat_vector(
+; CHECK-SAME: <2 x i8> [[X:%.*]]) {
+; CHECK-NEXT:    [[ADD:%.*]] = or <2 x i8> [[X]], splat (i8 1)
+; CHECK-NEXT:    [[CMP_INV:%.*]] = icmp slt <2 x i8> [[X]], splat (i8 1)
+; CHECK-NEXT:    [[S:%.*]] = select <2 x i1> [[CMP_INV]], <2 x i8> splat (i8 1), <2 x i8> [[ADD]]
+; CHECK-NEXT:    ret <2 x i8> [[S]]
+;
+  %add = or <2 x i8> %x, <i8 1, i8 1>
+  %cmp = icmp sgt <2 x i8> %x, <i8 0, i8 0>
+  %s = select <2 x i1> %cmp, <2 x i8> %add, <2 x i8> <i8 1, i8 1>
+  ret <2 x i8> %s
+}
+
+define i8 @const_operands_dont_fold_negative(i8 %x) {
+; CHECK-LABEL: define i8 @const_operands_dont_fold_negative(
+; CHECK-SAME: i8 [[X:%.*]]) {
+; CHECK-NEXT:    [[ADD:%.*]] = add nsw i8 [[X]], 16
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 [[X]], 18
+; CHECK-NEXT:    [[S:%.*]] = select i1 [[CMP]], i8 [[ADD]], i8 25
+; CHECK-NEXT:    ret i8 [[S]]
+;
+  %add = add nsw i8 %x, 16
+  %cmp = icmp sgt i8 %x, 18
+  %s = select i1 %cmp, i8 %add, i8 25
+  ret i8 %s
+}
+
+define i8 @add_with_poison_negative(i8 %x) {
+; CHECK-LABEL: define i8 @add_with_poison_negative(
+; CHECK-SAME: i8 [[X:%.*]]) {
+; CHECK-NEXT:    ret i8 25
+;
+  %add = add nsw i8 %x, poison
+  %cmp = icmp sgt i8 %x, 8
+  %s = select i1 %cmp, i8 %add, i8 25
+  ret i8 %s
+}
+
+define i8 @add_with_overflow_negative(i8 %x) {
+; CHECK-LABEL: define i8 @add_with_overflow_negative(
+; CHECK-SAME: i8 [[X:%.*]]) {
+; CHECK-NEXT:    [[ADD:%.*]] = add i8 [[X]], 100
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 [[X]], 119
+; CHECK-NEXT:    [[S:%.*]] = select i1 [[CMP]], i8 -127, i8 [[ADD]]
+; CHECK-NEXT:    ret i8 [[S]]
+;
+  %add = add i8 %x, 100
+  %cmp = icmp sle i8 120, %x
+  %s = select i1 %cmp, i8 -127, i8 %add
+  ret i8 %s
+}
+
+define <2 x i8> @vector_with_poison_negative(<2 x i8> %x) {
+; CHECK-LABEL: define <2 x i8> @vector_with_poison_negative(
+; CHECK-SAME: <2 x i8> [[X:%.*]]) {
+; CHECK-NEXT:    [[ADD:%.*]] = xor <2 x i8> [[X]], <i8 1, i8 poison>
+; CHECK-NEXT:    [[CMP_INV:%.*]] = icmp slt <2 x i8> [[X]], splat (i8 1)
+; CHECK-NEXT:    [[S:%.*]] = select <2 x i1> [[CMP_INV]], <2 x i8> splat (i8 1), <2 x i8> [[ADD]]
+; CHECK-NEXT:    ret <2 x i8> [[S]]
+;
+  %add = xor <2 x i8> %x, <i8 1, i8 poison>
+  %cmp = icmp sgt <2 x i8> %x, <i8 0, i8 0>
+  %s = select <2 x i1> %cmp, <2 x i8> %add, <2 x i8> <i8 1, i8 1>
+  ret <2 x i8> %s
+}
+
+define i8 @multi_use_bop_negative(i8 %x) {
+; CHECK-LABEL: define i8 @multi_use_bop_negative(
+; CHECK-SAME: i8 [[X:%.*]]) {
+; CHECK-NEXT:    [[ADD:%.*]] = add nsw i8 [[X]], 16
+; CHECK-NEXT:    call void @use_byte(i8 [[ADD]])
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 [[X]], 7
+; CHECK-NEXT:    [[S:%.*]] = select i1 [[CMP]], i8 24, i8 [[ADD]]
+; CHECK-NEXT:    ret i8 [[S]]
+;
+  %add = add nsw i8 %x, 16
+  call void @use_byte(i8 %add)
+  %cmp = icmp sle i8 8, %x
+  %s = select i1 %cmp, i8 24, i8 %add
+  ret i8 %s
+}
+
+define half @float_negative(half %x) {
+; CHECK-LABEL: define half @float_negative(
+; CHECK-SAME: half [[X:%.*]]) {
+; CHECK-NEXT:    [[ADD:%.*]] = fmul fast half [[X]], 0xH2E66
+; CHECK-NEXT:    [[CMP:%.*]] = fcmp ugt half [[X]], 0xH5640
+; CHECK-NEXT:    [[S:%.*]] = select i1 [[CMP]], half 0xH4900, half [[ADD]]
+; CHECK-NEXT:    ret half [[S]]
+;
+  %add = fdiv fast half %x, 10.0
+  %cmp = fcmp ult half 100.0, %x
+  %s = select i1 %cmp, half 10.0, half %add
+  ret half %s
+}
+
+define i8 @poison_false_val_negative(i8 %x) {
+; CHECK-LABEL: define i8 @poison_false_val_negative(
+; CHECK-SAME: i8 [[X:%.*]]) {
+; CHECK-NEXT:    [[ADD:%.*]] = add nsw i8 [[X]], 16
+; CHECK-NEXT:    ret i8 [[ADD]]
+;
+  %add = add nsw i8 %x, 16
+  %cmp = icmp sgt i8 %x, 8
+  %s = select i1 %cmp, i8 %add, i8 poison
+  ret i8 %s
+}
+
+define i8 @eq_negative(i8 %x) {
+; CHECK-LABEL: define i8 @eq_negative(
+; CHECK-SAME: i8 [[X:%.*]]) {
+; CHECK-NEXT:    ret i8 24
+;
+  %add = add nsw i8 %x, 16
+  %cmp = icmp eq i8 %x, 8
+  %s = select i1 %cmp, i8 %add, i8 24
+  ret i8 %s
+}
+
+define i8 @different_operands_negative(i8 %x, i8 %y) {
+; CHECK-LABEL: define i8 @different_operands_negative(
+; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) {
+; CHECK-NEXT:    [[ADD:%.*]] = add nsw i8 [[X]], 16
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 [[Y]], 8
+; CHECK-NEXT:    [[S:%.*]] = select i1 [[CMP]], i8 [[ADD]], i8 24
+; CHECK-NEXT:    ret i8 [[S]]
+;
+  %add = add nsw i8 %x, 16
+  %cmp = icmp sgt i8 %y, 8
+  %s = select i1 %cmp, i8 %add, i8 24
+  ret i8 %s
+}
+
+define i8 @non_const_bop_operand_negative(i8 %x, i8 %y) {
+; CHECK-LABEL: define i8 @non_const_bop_operand_negative(
+; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) {
+; CHECK-NEXT:    [[ADD:%.*]] = add nsw i8 [[X]], [[Y]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 [[Y]], 8
+; CHECK-NEXT:    [[S:%.*]] = select i1 [[CMP]], i8 [[ADD]], i8 24
+; CHECK-NEXT:    ret i8 [[S]]
+;
+  %add = add nsw i8 %x, %y
+  %cmp = icmp sgt i8 %y, 8
+  %s = select i1 %cmp, i8 %add, i8 24
+  ret i8 %s
+}
+
+define i8 @non_const_cmp_operand_negative(i8 %x, i8 %y) {
+; CHECK-LABEL: define i8 @non_const_cmp_operand_negative(
+; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) {
+; CHECK-NEXT:    [[ADD:%.*]] = add nsw i8 [[X]], 16
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 [[X]], [[Y]]
+; CHECK-NEXT:    [[S:%.*]] = select i1 [[CMP]], i8 [[ADD]], i8 24
+; CHECK-NEXT:    ret i8 [[S]]
+;
+  %add = add nsw i8 %x, 16
+  %cmp = icmp sgt i8 %x, %y
+  %s = select i1 %cmp, i8 %add, i8 24
+  ret i8 %s
+}
+
+declare i8 @result()
+
+define i8 @non_binop_negative(i8 %x) {
+; CHECK-LABEL: define i8 @non_binop_negative(
+; CHECK-SAME: i8 [[X:%.*]]) {
+; CHECK-NEXT:    [[RESULT:%.*]] = call i8 @result()
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 [[X]], 16
+; CHECK-NEXT:    [[S:%.*]] = select i1 [[CMP]], i8 [[RESULT]], i8 24
+; CHECK-NEXT:    ret i8 [[S]]
+;
+  %result = call i8 @result()
+  %cmp = icmp sgt i8 %x, 16
+  %s = select i1 %cmp, i8 %result, i8 24
+  ret i8 %s
+}
+
+define i8 @sub_const_on_lhs_negative(i8 %x) {
+; CHECK-LABEL: define i8 @sub_const_on_lhs_negative(
+; CHECK-SAME: i8 [[X:%.*]]) {
+; CHECK-NEXT:    [[SUB:%.*]] = sub nsw i8 50, [[X]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i8 [[X]], 100
+; CHECK-NEXT:    [[S:%.*]] = select i1 [[CMP]], i8 [[SUB]], i8 50
+; CHECK-NEXT:    ret i8 [[S]]
+;
+  %sub = sub nsw i8 50, %x
+  %cmp = icmp ugt i8 %x, 100
+  %s = select i1 %cmp, i8 %sub, i8 50
+  ret i8 %s
+}

>From f63b7be296a415bc7a4d4eadd6b15bc1469369bc Mon Sep 17 00:00:00 2001
From: Veera <sveera.2001 at gmail.com>
Date: Fri, 29 Nov 2024 02:20:14 +0000
Subject: [PATCH 2/2] Fold Select with Const Operand to BinOp

---
 clang/test/CodeGen/attr-counted-by.c          | 44 +++++------
 llvm/include/llvm/Analysis/ValueTracking.h    | 10 +++
 llvm/lib/Analysis/ValueTracking.cpp           | 69 +++++++++++------
 .../InstCombine/InstCombineSelect.cpp         | 75 ++++++++++++++-----
 .../InstCombine/canonicalize-const-to-bop.ll  | 67 +++++++----------
 .../Transforms/InstCombine/minmax-fold.ll     |  7 +-
 .../InstCombine/saturating-add-sub.ll         |  7 +-
 llvm/test/Transforms/InstCombine/select.ll    |  7 +-
 .../InstCombine/unsigned_saturated_sub.ll     | 25 +++----
 9 files changed, 180 insertions(+), 131 deletions(-)

diff --git a/clang/test/CodeGen/attr-counted-by.c b/clang/test/CodeGen/attr-counted-by.c
index f70e552bca26ab..d3f12bc5e07abc 100644
--- a/clang/test/CodeGen/attr-counted-by.c
+++ b/clang/test/CodeGen/attr-counted-by.c
@@ -119,9 +119,8 @@ void test1(struct annotated *p, int index, int val) {
 // SANITIZE-WITH-ATTR:       cont3:
 // SANITIZE-WITH-ATTR-NEXT:    [[ARRAY:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 12
 // SANITIZE-WITH-ATTR-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds nuw [0 x i32], ptr [[ARRAY]], i64 0, i64 [[INDEX]]
-// SANITIZE-WITH-ATTR-NEXT:    [[TMP2:%.*]] = shl i32 [[DOT_COUNTED_BY_LOAD]], 2
-// SANITIZE-WITH-ATTR-NEXT:    [[DOTINV:%.*]] = icmp slt i32 [[DOT_COUNTED_BY_LOAD]], 0
-// SANITIZE-WITH-ATTR-NEXT:    [[CONV:%.*]] = select i1 [[DOTINV]], i32 0, i32 [[TMP2]]
+// SANITIZE-WITH-ATTR-NEXT:    [[TMP2:%.*]] = tail call i32 @llvm.smax.i32(i32 [[DOT_COUNTED_BY_LOAD]], i32 0)
+// SANITIZE-WITH-ATTR-NEXT:    [[CONV:%.*]] = shl i32 [[TMP2]], 2
 // SANITIZE-WITH-ATTR-NEXT:    store i32 [[CONV]], ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA4]]
 // SANITIZE-WITH-ATTR-NEXT:    ret void
 //
@@ -130,9 +129,8 @@ void test1(struct annotated *p, int index, int val) {
 // NO-SANITIZE-WITH-ATTR-NEXT:  entry:
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 8
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_LOAD:%.*]] = load i32, ptr [[DOT_COUNTED_BY_GEP]], align 4
-// NO-SANITIZE-WITH-ATTR-NEXT:    [[TMP0:%.*]] = shl i32 [[DOT_COUNTED_BY_LOAD]], 2
-// NO-SANITIZE-WITH-ATTR-NEXT:    [[DOTINV:%.*]] = icmp slt i32 [[DOT_COUNTED_BY_LOAD]], 0
-// NO-SANITIZE-WITH-ATTR-NEXT:    [[CONV:%.*]] = select i1 [[DOTINV]], i32 0, i32 [[TMP0]]
+// NO-SANITIZE-WITH-ATTR-NEXT:    [[TMP0:%.*]] = tail call i32 @llvm.smax.i32(i32 [[DOT_COUNTED_BY_LOAD]], i32 0)
+// NO-SANITIZE-WITH-ATTR-NEXT:    [[CONV:%.*]] = shl i32 [[TMP0]], 2
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[ARRAY:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 12
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds nuw [0 x i32], ptr [[ARRAY]], i64 0, i64 [[INDEX]]
 // NO-SANITIZE-WITH-ATTR-NEXT:    store i32 [[CONV]], ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]]
@@ -539,10 +537,9 @@ size_t test5_bdos(struct anon_struct *p) {
 // SANITIZE-WITH-ATTR:       cont3:
 // SANITIZE-WITH-ATTR-NEXT:    [[TMP1:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 16
 // SANITIZE-WITH-ATTR-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i32], ptr [[TMP1]], i64 0, i64 [[IDXPROM]]
-// SANITIZE-WITH-ATTR-NEXT:    [[DOTINV:%.*]] = icmp slt i64 [[DOT_COUNTED_BY_LOAD]], 0
-// SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_LOAD_TR:%.*]] = trunc i64 [[DOT_COUNTED_BY_LOAD]] to i32
-// SANITIZE-WITH-ATTR-NEXT:    [[TMP2:%.*]] = shl i32 [[DOT_COUNTED_BY_LOAD_TR]], 2
-// SANITIZE-WITH-ATTR-NEXT:    [[CONV:%.*]] = select i1 [[DOTINV]], i32 0, i32 [[TMP2]]
+// SANITIZE-WITH-ATTR-NEXT:    [[TMP2:%.*]] = tail call i64 @llvm.smax.i64(i64 [[DOT_COUNTED_BY_LOAD]], i64 0)
+// SANITIZE-WITH-ATTR-NEXT:    [[DOTTR:%.*]] = trunc i64 [[TMP2]] to i32
+// SANITIZE-WITH-ATTR-NEXT:    [[CONV:%.*]] = shl i32 [[DOTTR]], 2
 // SANITIZE-WITH-ATTR-NEXT:    store i32 [[CONV]], ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA4]]
 // SANITIZE-WITH-ATTR-NEXT:    ret void
 //
@@ -551,10 +548,9 @@ size_t test5_bdos(struct anon_struct *p) {
 // NO-SANITIZE-WITH-ATTR-NEXT:  entry:
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 8
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_LOAD:%.*]] = load i64, ptr [[DOT_COUNTED_BY_GEP]], align 4
-// NO-SANITIZE-WITH-ATTR-NEXT:    [[DOTINV:%.*]] = icmp slt i64 [[DOT_COUNTED_BY_LOAD]], 0
-// NO-SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_LOAD_TR:%.*]] = trunc i64 [[DOT_COUNTED_BY_LOAD]] to i32
-// NO-SANITIZE-WITH-ATTR-NEXT:    [[TMP0:%.*]] = shl i32 [[DOT_COUNTED_BY_LOAD_TR]], 2
-// NO-SANITIZE-WITH-ATTR-NEXT:    [[CONV:%.*]] = select i1 [[DOTINV]], i32 0, i32 [[TMP0]]
+// NO-SANITIZE-WITH-ATTR-NEXT:    [[TMP0:%.*]] = tail call i64 @llvm.smax.i64(i64 [[DOT_COUNTED_BY_LOAD]], i64 0)
+// NO-SANITIZE-WITH-ATTR-NEXT:    [[DOTTR:%.*]] = trunc i64 [[TMP0]] to i32
+// NO-SANITIZE-WITH-ATTR-NEXT:    [[CONV:%.*]] = shl i32 [[DOTTR]], 2
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[TMP1:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 16
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i32], ptr [[TMP1]], i64 0, i64 [[IDXPROM]]
@@ -588,9 +584,8 @@ void test6(struct anon_struct *p, int index) {
 // SANITIZE-WITH-ATTR-NEXT:  entry:
 // SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 8
 // SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_LOAD:%.*]] = load i64, ptr [[DOT_COUNTED_BY_GEP]], align 4
-// SANITIZE-WITH-ATTR-NEXT:    [[TMP0:%.*]] = shl nuw i64 [[DOT_COUNTED_BY_LOAD]], 2
-// SANITIZE-WITH-ATTR-NEXT:    [[DOTINV:%.*]] = icmp slt i64 [[DOT_COUNTED_BY_LOAD]], 0
-// SANITIZE-WITH-ATTR-NEXT:    [[TMP1:%.*]] = select i1 [[DOTINV]], i64 0, i64 [[TMP0]]
+// SANITIZE-WITH-ATTR-NEXT:    [[TMP0:%.*]] = tail call i64 @llvm.smax.i64(i64 [[DOT_COUNTED_BY_LOAD]], i64 0)
+// SANITIZE-WITH-ATTR-NEXT:    [[TMP1:%.*]] = shl i64 [[TMP0]], 2
 // SANITIZE-WITH-ATTR-NEXT:    ret i64 [[TMP1]]
 //
 // NO-SANITIZE-WITH-ATTR-LABEL: define dso_local range(i64 0, -3) i64 @test6_bdos(
@@ -598,9 +593,8 @@ void test6(struct anon_struct *p, int index) {
 // NO-SANITIZE-WITH-ATTR-NEXT:  entry:
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 8
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_LOAD:%.*]] = load i64, ptr [[DOT_COUNTED_BY_GEP]], align 4
-// NO-SANITIZE-WITH-ATTR-NEXT:    [[TMP0:%.*]] = shl nuw i64 [[DOT_COUNTED_BY_LOAD]], 2
-// NO-SANITIZE-WITH-ATTR-NEXT:    [[DOTINV:%.*]] = icmp slt i64 [[DOT_COUNTED_BY_LOAD]], 0
-// NO-SANITIZE-WITH-ATTR-NEXT:    [[TMP1:%.*]] = select i1 [[DOTINV]], i64 0, i64 [[TMP0]]
+// NO-SANITIZE-WITH-ATTR-NEXT:    [[TMP0:%.*]] = tail call i64 @llvm.smax.i64(i64 [[DOT_COUNTED_BY_LOAD]], i64 0)
+// NO-SANITIZE-WITH-ATTR-NEXT:    [[TMP1:%.*]] = shl i64 [[TMP0]], 2
 // NO-SANITIZE-WITH-ATTR-NEXT:    ret i64 [[TMP1]]
 //
 // SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i64 @test6_bdos(
@@ -1740,9 +1734,8 @@ struct annotated_struct_array {
 // SANITIZE-WITH-ATTR:       cont20:
 // SANITIZE-WITH-ATTR-NEXT:    [[ARRAY:%.*]] = getelementptr inbounds nuw i8, ptr [[TMP2]], i64 12
 // SANITIZE-WITH-ATTR-NEXT:    [[ARRAYIDX18:%.*]] = getelementptr inbounds [0 x i32], ptr [[ARRAY]], i64 0, i64 [[IDXPROM15]]
-// SANITIZE-WITH-ATTR-NEXT:    [[TMP5:%.*]] = shl i32 [[DOT_COUNTED_BY_LOAD]], 2
-// SANITIZE-WITH-ATTR-NEXT:    [[DOTINV:%.*]] = icmp slt i32 [[DOT_COUNTED_BY_LOAD]], 0
-// SANITIZE-WITH-ATTR-NEXT:    [[CONV:%.*]] = select i1 [[DOTINV]], i32 0, i32 [[TMP5]]
+// SANITIZE-WITH-ATTR-NEXT:    [[TMP5:%.*]] = tail call i32 @llvm.smax.i32(i32 [[DOT_COUNTED_BY_LOAD]], i32 0)
+// SANITIZE-WITH-ATTR-NEXT:    [[CONV:%.*]] = shl i32 [[TMP5]], 2
 // SANITIZE-WITH-ATTR-NEXT:    store i32 [[CONV]], ptr [[ARRAYIDX18]], align 4, !tbaa [[TBAA4]]
 // SANITIZE-WITH-ATTR-NEXT:    ret void
 //
@@ -1754,9 +1747,8 @@ struct annotated_struct_array {
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[ARRAYIDX]], align 8, !tbaa [[TBAA11]]
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[TMP0]], i64 8
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_LOAD:%.*]] = load i32, ptr [[DOT_COUNTED_BY_GEP]], align 4
-// NO-SANITIZE-WITH-ATTR-NEXT:    [[TMP1:%.*]] = shl i32 [[DOT_COUNTED_BY_LOAD]], 2
-// NO-SANITIZE-WITH-ATTR-NEXT:    [[DOTINV:%.*]] = icmp slt i32 [[DOT_COUNTED_BY_LOAD]], 0
-// NO-SANITIZE-WITH-ATTR-NEXT:    [[CONV:%.*]] = select i1 [[DOTINV]], i32 0, i32 [[TMP1]]
+// NO-SANITIZE-WITH-ATTR-NEXT:    [[TMP1:%.*]] = tail call i32 @llvm.smax.i32(i32 [[DOT_COUNTED_BY_LOAD]], i32 0)
+// NO-SANITIZE-WITH-ATTR-NEXT:    [[CONV:%.*]] = shl i32 [[TMP1]], 2
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[ARRAY:%.*]] = getelementptr inbounds nuw i8, ptr [[TMP0]], i64 12
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[IDXPROM4:%.*]] = sext i32 [[IDX2]] to i64
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[ARRAYIDX5:%.*]] = getelementptr inbounds [0 x i32], ptr [[ARRAY]], i64 0, i64 [[IDXPROM4]]
diff --git a/llvm/include/llvm/Analysis/ValueTracking.h b/llvm/include/llvm/Analysis/ValueTracking.h
index 2b0377903ac8e3..bd74d27e0c49b1 100644
--- a/llvm/include/llvm/Analysis/ValueTracking.h
+++ b/llvm/include/llvm/Analysis/ValueTracking.h
@@ -1178,10 +1178,20 @@ SelectPatternResult matchDecomposedSelectPattern(
     CmpInst *CmpI, Value *TrueVal, Value *FalseVal, Value *&LHS, Value *&RHS,
     Instruction::CastOps *CastOp = nullptr, unsigned Depth = 0);
 
+/// Determine the pattern for predicate `X Pred Y ? X : Y`.
+SelectPatternResult
+getSelectPattern(CmpInst::Predicate Pred,
+                 SelectPatternNaNBehavior NaNBehavior = SPNB_NA,
+                 bool Ordered = false);
+
 /// Return the canonical comparison predicate for the specified
 /// minimum/maximum flavor.
 CmpInst::Predicate getMinMaxPred(SelectPatternFlavor SPF, bool Ordered = false);
 
+/// Convert given `SPF` to equivalent min/max intrinsic.
+/// Caller must ensure `SPF` is an integer min or max pattern.
+Intrinsic::ID getMinMaxIntrinsic(SelectPatternFlavor SPF);
+
 /// Return the inverse minimum/maximum flavor of the specified flavor.
 /// For example, signed minimum is the inverse of signed maximum.
 SelectPatternFlavor getInverseMinMaxFlavor(SelectPatternFlavor SPF);
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index c48068afc04816..25740473fd5a14 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -8589,6 +8589,37 @@ bool llvm::isKnownInversion(const Value *X, const Value *Y) {
   return CR1.inverse() == CR2;
 }
 
+SelectPatternResult llvm::getSelectPattern(CmpInst::Predicate Pred,
+                                           SelectPatternNaNBehavior NaNBehavior,
+                                           bool Ordered) {
+  switch (Pred) {
+  default:
+    return {SPF_UNKNOWN, SPNB_NA, false}; // Equality.
+  case ICmpInst::ICMP_UGT:
+  case ICmpInst::ICMP_UGE:
+    return {SPF_UMAX, SPNB_NA, false};
+  case ICmpInst::ICMP_SGT:
+  case ICmpInst::ICMP_SGE:
+    return {SPF_SMAX, SPNB_NA, false};
+  case ICmpInst::ICMP_ULT:
+  case ICmpInst::ICMP_ULE:
+    return {SPF_UMIN, SPNB_NA, false};
+  case ICmpInst::ICMP_SLT:
+  case ICmpInst::ICMP_SLE:
+    return {SPF_SMIN, SPNB_NA, false};
+  case FCmpInst::FCMP_UGT:
+  case FCmpInst::FCMP_UGE:
+  case FCmpInst::FCMP_OGT:
+  case FCmpInst::FCMP_OGE:
+    return {SPF_FMAXNUM, NaNBehavior, Ordered};
+  case FCmpInst::FCMP_ULT:
+  case FCmpInst::FCMP_ULE:
+  case FCmpInst::FCMP_OLT:
+  case FCmpInst::FCMP_OLE:
+    return {SPF_FMINNUM, NaNBehavior, Ordered};
+  }
+}
+
 static SelectPatternResult matchSelectPattern(CmpInst::Predicate Pred,
                                               FastMathFlags FMF,
                                               Value *CmpLHS, Value *CmpRHS,
@@ -8696,27 +8727,8 @@ static SelectPatternResult matchSelectPattern(CmpInst::Predicate Pred,
   }
 
   // ([if]cmp X, Y) ? X : Y
-  if (TrueVal == CmpLHS && FalseVal == CmpRHS) {
-    switch (Pred) {
-    default: return {SPF_UNKNOWN, SPNB_NA, false}; // Equality.
-    case ICmpInst::ICMP_UGT:
-    case ICmpInst::ICMP_UGE: return {SPF_UMAX, SPNB_NA, false};
-    case ICmpInst::ICMP_SGT:
-    case ICmpInst::ICMP_SGE: return {SPF_SMAX, SPNB_NA, false};
-    case ICmpInst::ICMP_ULT:
-    case ICmpInst::ICMP_ULE: return {SPF_UMIN, SPNB_NA, false};
-    case ICmpInst::ICMP_SLT:
-    case ICmpInst::ICMP_SLE: return {SPF_SMIN, SPNB_NA, false};
-    case FCmpInst::FCMP_UGT:
-    case FCmpInst::FCMP_UGE:
-    case FCmpInst::FCMP_OGT:
-    case FCmpInst::FCMP_OGE: return {SPF_FMAXNUM, NaNBehavior, Ordered};
-    case FCmpInst::FCMP_ULT:
-    case FCmpInst::FCMP_ULE:
-    case FCmpInst::FCMP_OLT:
-    case FCmpInst::FCMP_OLE: return {SPF_FMINNUM, NaNBehavior, Ordered};
-    }
-  }
+  if (TrueVal == CmpLHS && FalseVal == CmpRHS)
+    return getSelectPattern(Pred, NaNBehavior, Ordered);
 
   if (isKnownNegation(TrueVal, FalseVal)) {
     // Sign-extending LHS does not change its sign, so TrueVal/FalseVal can
@@ -8960,6 +8972,21 @@ CmpInst::Predicate llvm::getMinMaxPred(SelectPatternFlavor SPF, bool Ordered) {
   llvm_unreachable("unhandled!");
 }
 
+Intrinsic::ID llvm::getMinMaxIntrinsic(SelectPatternFlavor SPF) {
+  switch (SPF) {
+  case SelectPatternFlavor::SPF_UMIN:
+    return Intrinsic::umin;
+  case SelectPatternFlavor::SPF_UMAX:
+    return Intrinsic::umax;
+  case SelectPatternFlavor::SPF_SMIN:
+    return Intrinsic::smin;
+  case SelectPatternFlavor::SPF_SMAX:
+    return Intrinsic::smax;
+  default:
+    llvm_unreachable("Unexpected SPF");
+  }
+}
+
 SelectPatternFlavor llvm::getInverseMinMaxFlavor(SelectPatternFlavor SPF) {
   if (SPF == SPF_SMIN) return SPF_SMAX;
   if (SPF == SPF_UMIN) return SPF_UMAX;
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index e5525133e5dbb5..027a45b95a6de3 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -1257,23 +1257,7 @@ static Value *canonicalizeSPF(ICmpInst &Cmp, Value *TrueVal, Value *FalseVal,
   }
 
   if (SelectPatternResult::isMinOrMax(SPF)) {
-    Intrinsic::ID IntrinsicID;
-    switch (SPF) {
-    case SelectPatternFlavor::SPF_UMIN:
-      IntrinsicID = Intrinsic::umin;
-      break;
-    case SelectPatternFlavor::SPF_UMAX:
-      IntrinsicID = Intrinsic::umax;
-      break;
-    case SelectPatternFlavor::SPF_SMIN:
-      IntrinsicID = Intrinsic::smin;
-      break;
-    case SelectPatternFlavor::SPF_SMAX:
-      IntrinsicID = Intrinsic::smax;
-      break;
-    default:
-      llvm_unreachable("Unexpected SPF");
-    }
+    Intrinsic::ID IntrinsicID = getMinMaxIntrinsic(SPF);
     return IC.Builder.CreateBinaryIntrinsic(IntrinsicID, LHS, RHS);
   }
 
@@ -1898,6 +1882,60 @@ static Instruction *foldSelectICmpEq(SelectInst &SI, ICmpInst *ICI,
   return nullptr;
 }
 
+/// Fold `X Pred C1 ? X BOp C2 : C1 BOp C2` to `min/max(X, C1) BOp C2`.
+/// This allows for better canonicalization.
+static Value *foldSelectWithConstOpToBinOp(ICmpInst *Cmp, Value *TrueVal,
+                                           Value *FalseVal,
+                                           IRBuilderBase &Builder) {
+  BinaryOperator *BOp;
+  Constant *C1, *C2, *C3;
+  Value *X;
+  ICmpInst::Predicate Predicate;
+
+  if (!match(Cmp, m_ICmp(Predicate, m_Value(X), m_Constant(C1))))
+    return nullptr;
+
+  if (!ICmpInst::isRelational(Predicate))
+    return nullptr;
+
+  if (match(TrueVal, m_Constant())) {
+    std::swap(FalseVal, TrueVal);
+    Predicate = ICmpInst::getInversePredicate(Predicate);
+  }
+
+  if (!match(TrueVal, m_BinOp(BOp)) || !match(FalseVal, m_Constant(C3)))
+    return nullptr;
+
+  unsigned Opcode = BOp->getOpcode();
+
+  if (Instruction::isIntDivRem(Opcode))
+    return nullptr;
+
+  if (!match(BOp, m_OneUse(m_BinOp(m_Specific(X), m_Constant(C2)))))
+    return nullptr;
+
+  Value *RHS;
+  SelectPatternFlavor SPF;
+  const DataLayout &Layout = BOp->getDataLayout();
+  auto Flipped =
+      InstCombiner::getFlippedStrictnessPredicateAndConstant(Predicate, C1);
+
+  if (C3 == ConstantFoldBinaryOpOperands(Opcode, C1, C2, Layout)) {
+    SPF = getSelectPattern(Predicate).Flavor;
+    RHS = C1;
+  } else if (Flipped && C3 == ConstantFoldBinaryOpOperands(
+                                  Opcode, Flipped->second, C2, Layout)) {
+    SPF = getSelectPattern(Flipped->first).Flavor;
+    RHS = Flipped->second;
+  } else {
+    return nullptr;
+  }
+
+  Intrinsic::ID IntrinsicID = getMinMaxIntrinsic(SPF);
+  Value *Intrinsic = Builder.CreateBinaryIntrinsic(IntrinsicID, X, RHS);
+  return Builder.CreateBinOp(BOp->getOpcode(), Intrinsic, C2);
+}
+
 /// Visit a SelectInst that has an ICmpInst as its first operand.
 Instruction *InstCombinerImpl::foldSelectInstWithICmp(SelectInst &SI,
                                                       ICmpInst *ICI) {
@@ -1987,6 +2025,9 @@ Instruction *InstCombinerImpl::foldSelectInstWithICmp(SelectInst &SI,
   if (Value *V = foldAbsDiff(ICI, TrueVal, FalseVal, Builder))
     return replaceInstUsesWith(SI, V);
 
+  if (Value *V = foldSelectWithConstOpToBinOp(ICI, TrueVal, FalseVal, Builder))
+    return replaceInstUsesWith(SI, V);
+
   return Changed ? &SI : nullptr;
 }
 
diff --git a/llvm/test/Transforms/InstCombine/canonicalize-const-to-bop.ll b/llvm/test/Transforms/InstCombine/canonicalize-const-to-bop.ll
index a23fc84aebd2e3..68049ca230191e 100644
--- a/llvm/test/Transforms/InstCombine/canonicalize-const-to-bop.ll
+++ b/llvm/test/Transforms/InstCombine/canonicalize-const-to-bop.ll
@@ -4,9 +4,8 @@
 define i8 @add_and_sgt(i8 %x) {
 ; CHECK-LABEL: define i8 @add_and_sgt(
 ; CHECK-SAME: i8 [[X:%.*]]) {
-; CHECK-NEXT:    [[ADD:%.*]] = add nsw i8 [[X]], 16
-; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 [[X]], 8
-; CHECK-NEXT:    [[S:%.*]] = select i1 [[CMP]], i8 [[ADD]], i8 24
+; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.smax.i8(i8 [[X]], i8 8)
+; CHECK-NEXT:    [[S:%.*]] = add nuw i8 [[TMP1]], 16
 ; CHECK-NEXT:    ret i8 [[S]]
 ;
   %add = add nsw i8 %x, 16
@@ -18,9 +17,8 @@ define i8 @add_and_sgt(i8 %x) {
 define i8 @add_sgt_nuw(i8 %x) {
 ; CHECK-LABEL: define i8 @add_sgt_nuw(
 ; CHECK-SAME: i8 [[X:%.*]]) {
-; CHECK-NEXT:    [[ADD:%.*]] = add nuw i8 [[X]], 16
-; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 [[X]], 8
-; CHECK-NEXT:    [[S:%.*]] = select i1 [[CMP]], i8 [[ADD]], i8 24
+; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.smax.i8(i8 [[X]], i8 8)
+; CHECK-NEXT:    [[S:%.*]] = add nuw i8 [[TMP1]], 16
 ; CHECK-NEXT:    ret i8 [[S]]
 ;
   %add = add nuw i8 %x, 16
@@ -32,9 +30,8 @@ define i8 @add_sgt_nuw(i8 %x) {
 define i8 @sub_and_ugt(i8 %x) {
 ; CHECK-LABEL: define i8 @sub_and_ugt(
 ; CHECK-SAME: i8 [[X:%.*]]) {
-; CHECK-NEXT:    [[SUB:%.*]] = add nsw i8 [[X]], -50
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i8 [[X]], 100
-; CHECK-NEXT:    [[S:%.*]] = select i1 [[CMP]], i8 50, i8 [[SUB]]
+; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.umin.i8(i8 [[X]], i8 100)
+; CHECK-NEXT:    [[S:%.*]] = add nsw i8 [[TMP1]], -50
 ; CHECK-NEXT:    ret i8 [[S]]
 ;
   %sub = sub nsw i8 %x, 50
@@ -46,9 +43,8 @@ define i8 @sub_and_ugt(i8 %x) {
 define i8 @sub_ugt_nuw_nsw(i8 %x) {
 ; CHECK-LABEL: define i8 @sub_ugt_nuw_nsw(
 ; CHECK-SAME: i8 [[X:%.*]]) {
-; CHECK-NEXT:    [[SUB:%.*]] = add nsw i8 [[X]], -50
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i8 [[X]], 100
-; CHECK-NEXT:    [[S:%.*]] = select i1 [[CMP]], i8 50, i8 [[SUB]]
+; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.umin.i8(i8 [[X]], i8 100)
+; CHECK-NEXT:    [[S:%.*]] = add nsw i8 [[TMP1]], -50
 ; CHECK-NEXT:    ret i8 [[S]]
 ;
   %sub = sub nuw nsw i8 %x, 50
@@ -60,9 +56,8 @@ define i8 @sub_ugt_nuw_nsw(i8 %x) {
 define i8 @mul_and_ult(i8 %x) {
 ; CHECK-LABEL: define i8 @mul_and_ult(
 ; CHECK-SAME: i8 [[X:%.*]]) {
-; CHECK-NEXT:    [[ADD:%.*]] = mul nsw i8 [[X]], 10
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i8 [[X]], 10
-; CHECK-NEXT:    [[S:%.*]] = select i1 [[CMP]], i8 100, i8 [[ADD]]
+; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.umin.i8(i8 [[X]], i8 10)
+; CHECK-NEXT:    [[S:%.*]] = mul nuw i8 [[TMP1]], 10
 ; CHECK-NEXT:    ret i8 [[S]]
 ;
   %add = mul nsw i8 %x, 10
@@ -74,9 +69,8 @@ define i8 @mul_and_ult(i8 %x) {
 define i8 @mul_and_non_strict_predicate(i8 %x) {
 ; CHECK-LABEL: define i8 @mul_and_non_strict_predicate(
 ; CHECK-SAME: i8 [[X:%.*]]) {
-; CHECK-NEXT:    [[ADD:%.*]] = mul nsw i8 [[X]], 10
-; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 [[X]], 9
-; CHECK-NEXT:    [[S:%.*]] = select i1 [[CMP]], i8 100, i8 [[ADD]]
+; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.smin.i8(i8 [[X]], i8 10)
+; CHECK-NEXT:    [[S:%.*]] = mul i8 [[TMP1]], 10
 ; CHECK-NEXT:    ret i8 [[S]]
 ;
   %add = mul nsw i8 %x, 10
@@ -88,9 +82,8 @@ define i8 @mul_and_non_strict_predicate(i8 %x) {
 define i8 @mul_ult_noflags(i8 %x) {
 ; CHECK-LABEL: define i8 @mul_ult_noflags(
 ; CHECK-SAME: i8 [[X:%.*]]) {
-; CHECK-NEXT:    [[ADD:%.*]] = mul i8 [[X]], 10
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i8 [[X]], 10
-; CHECK-NEXT:    [[S:%.*]] = select i1 [[CMP]], i8 100, i8 [[ADD]]
+; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.umin.i8(i8 [[X]], i8 10)
+; CHECK-NEXT:    [[S:%.*]] = mul nuw i8 [[TMP1]], 10
 ; CHECK-NEXT:    ret i8 [[S]]
 ;
   %add = mul i8 %x, 10
@@ -130,9 +123,8 @@ define i8 @udiv_slt_exact(i8 %x) {
 define i8 @canonicalize_icmp_operands(i8 %x) {
 ; CHECK-LABEL: define i8 @canonicalize_icmp_operands(
 ; CHECK-SAME: i8 [[X:%.*]]) {
-; CHECK-NEXT:    [[ADD:%.*]] = add nsw i8 [[X]], 8
-; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 [[X]], 119
-; CHECK-NEXT:    [[S:%.*]] = select i1 [[CMP]], i8 127, i8 [[ADD]]
+; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.smin.i8(i8 [[X]], i8 119)
+; CHECK-NEXT:    [[S:%.*]] = add nsw i8 [[TMP1]], 8
 ; CHECK-NEXT:    ret i8 [[S]]
 ;
   %add = add nsw i8 %x, 8
@@ -144,9 +136,8 @@ define i8 @canonicalize_icmp_operands(i8 %x) {
 define i8 @flipped_strictness_predicate_and_constant(i8 %x, i8 %y) {
 ; CHECK-LABEL: define i8 @flipped_strictness_predicate_and_constant(
 ; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) {
-; CHECK-NEXT:    [[A:%.*]] = add i8 [[X]], -2
-; CHECK-NEXT:    [[C:%.*]] = icmp ult i8 [[X]], 2
-; CHECK-NEXT:    [[R:%.*]] = select i1 [[C]], i8 -1, i8 [[A]]
+; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.umax.i8(i8 [[X]], i8 1)
+; CHECK-NEXT:    [[R:%.*]] = add i8 [[TMP1]], -2
 ; CHECK-NEXT:    ret i8 [[R]]
 ;
   %a = add i8 %x, -2
@@ -161,10 +152,10 @@ declare void @use_byte(i8)
 define i8 @multi_use_cond_and_sel(i8 %x) {
 ; CHECK-LABEL: define i8 @multi_use_cond_and_sel(
 ; CHECK-SAME: i8 [[X:%.*]]) {
-; CHECK-NEXT:    [[ADD:%.*]] = add nsw i8 [[X]], 16
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 [[X]], 8
 ; CHECK-NEXT:    call void @use(i1 [[CMP]])
-; CHECK-NEXT:    [[S:%.*]] = select i1 [[CMP]], i8 [[ADD]], i8 24
+; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.smax.i8(i8 [[X]], i8 8)
+; CHECK-NEXT:    [[S:%.*]] = add nuw i8 [[TMP1]], 16
 ; CHECK-NEXT:    call void @use_byte(i8 [[S]])
 ; CHECK-NEXT:    ret i8 [[S]]
 ;
@@ -183,11 +174,9 @@ define void @rust_noop_loop() {
 ; CHECK:       [[BB2_I]]:
 ; CHECK-NEXT:    [[ITER_SROA_0_07:%.*]] = phi i32 [ 0, %[[START]] ], [ [[SPEC_SELECT5:%.*]], %[[BB2_I]] ]
 ; CHECK-NEXT:    [[_0_I3_I:%.*]] = icmp sgt i32 [[ITER_SROA_0_07]], 99
-; CHECK-NEXT:    [[TMP0:%.*]] = add nsw i32 [[ITER_SROA_0_07]], 1
-; CHECK-NEXT:    [[SPEC_SELECT5]] = select i1 [[_0_I3_I]], i32 100, i32 [[TMP0]]
-; CHECK-NEXT:    [[_0_I_NOT_I:%.*]] = icmp sgt i32 [[SPEC_SELECT5]], 100
-; CHECK-NEXT:    [[OR_COND:%.*]] = select i1 [[_0_I3_I]], i1 true, i1 [[_0_I_NOT_I]]
-; CHECK-NEXT:    br i1 [[OR_COND]], label %[[BASICBLOCK4:.*]], label %[[BB2_I]]
+; CHECK-NEXT:    [[TMP0:%.*]] = call i32 @llvm.smin.i32(i32 [[ITER_SROA_0_07]], i32 99)
+; CHECK-NEXT:    [[SPEC_SELECT5]] = add nsw i32 [[TMP0]], 1
+; CHECK-NEXT:    br i1 [[_0_I3_I]], label %[[BASICBLOCK4:.*]], label %[[BB2_I]]
 ; CHECK:       [[BASICBLOCK4]]:
 ; CHECK-NEXT:    ret void
 ;
@@ -210,9 +199,8 @@ basicblock4:
 define <2 x i8> @add_non_splat_vector(<2 x i8> %x) {
 ; CHECK-LABEL: define <2 x i8> @add_non_splat_vector(
 ; CHECK-SAME: <2 x i8> [[X:%.*]]) {
-; CHECK-NEXT:    [[ADD:%.*]] = add <2 x i8> [[X]], <i8 1, i8 0>
-; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt <2 x i8> [[X]], <i8 0, i8 1>
-; CHECK-NEXT:    [[S:%.*]] = select <2 x i1> [[CMP]], <2 x i8> [[ADD]], <2 x i8> splat (i8 1)
+; CHECK-NEXT:    [[TMP1:%.*]] = call <2 x i8> @llvm.smax.v2i8(<2 x i8> [[X]], <2 x i8> <i8 0, i8 1>)
+; CHECK-NEXT:    [[S:%.*]] = add nuw <2 x i8> [[TMP1]], <i8 1, i8 0>
 ; CHECK-NEXT:    ret <2 x i8> [[S]]
 ;
   %add = add <2 x i8> %x, <i8 1, i8 0>
@@ -224,9 +212,8 @@ define <2 x i8> @add_non_splat_vector(<2 x i8> %x) {
 define <2 x i8> @or_splat_vector(<2 x i8> %x) {
 ; CHECK-LABEL: define <2 x i8> @or_splat_vector(
 ; CHECK-SAME: <2 x i8> [[X:%.*]]) {
-; CHECK-NEXT:    [[ADD:%.*]] = or <2 x i8> [[X]], splat (i8 1)
-; CHECK-NEXT:    [[CMP_INV:%.*]] = icmp slt <2 x i8> [[X]], splat (i8 1)
-; CHECK-NEXT:    [[S:%.*]] = select <2 x i1> [[CMP_INV]], <2 x i8> splat (i8 1), <2 x i8> [[ADD]]
+; CHECK-NEXT:    [[TMP1:%.*]] = call <2 x i8> @llvm.smax.v2i8(<2 x i8> [[X]], <2 x i8> splat (i8 1))
+; CHECK-NEXT:    [[S:%.*]] = or <2 x i8> [[TMP1]], splat (i8 1)
 ; CHECK-NEXT:    ret <2 x i8> [[S]]
 ;
   %add = or <2 x i8> %x, <i8 1, i8 1>
diff --git a/llvm/test/Transforms/InstCombine/minmax-fold.ll b/llvm/test/Transforms/InstCombine/minmax-fold.ll
index ccdf4400b16b54..2e267958d0476e 100644
--- a/llvm/test/Transforms/InstCombine/minmax-fold.ll
+++ b/llvm/test/Transforms/InstCombine/minmax-fold.ll
@@ -1358,11 +1358,10 @@ define i8 @PR14613_smax(i8 %x) {
 
 define i8 @PR46271(<2 x i8> %x) {
 ; CHECK-LABEL: @PR46271(
-; CHECK-NEXT:    [[TMP1:%.*]] = xor <2 x i8> [[X:%.*]], <i8 poison, i8 -1>
-; CHECK-NEXT:    [[A_INV:%.*]] = icmp slt <2 x i8> [[X]], zeroinitializer
-; CHECK-NEXT:    [[NOT:%.*]] = select <2 x i1> [[A_INV]], <2 x i8> <i8 poison, i8 0>, <2 x i8> [[TMP1]]
+; CHECK-NEXT:    [[NOT:%.*]] = call <2 x i8> @llvm.smax.v2i8(<2 x i8> [[X:%.*]], <2 x i8> splat (i8 -1))
 ; CHECK-NEXT:    [[R:%.*]] = extractelement <2 x i8> [[NOT]], i64 1
-; CHECK-NEXT:    ret i8 [[R]]
+; CHECK-NEXT:    [[R1:%.*]] = xor i8 [[R]], -1
+; CHECK-NEXT:    ret i8 [[R1]]
 ;
   %a = icmp sgt <2 x i8> %x, <i8 -1, i8 -1>
   %b = select <2 x i1> %a, <2 x i8> %x, <2 x i8> <i8 poison, i8 -1>
diff --git a/llvm/test/Transforms/InstCombine/saturating-add-sub.ll b/llvm/test/Transforms/InstCombine/saturating-add-sub.ll
index 9236d96f59a55b..e050ca762dad46 100644
--- a/llvm/test/Transforms/InstCombine/saturating-add-sub.ll
+++ b/llvm/test/Transforms/InstCombine/saturating-add-sub.ll
@@ -1793,10 +1793,9 @@ define i32 @not_uadd_sat(i32 %x, i32 %y) {
 
 define i32 @not_uadd_sat2(i32 %x, i32 %y) {
 ; CHECK-LABEL: @not_uadd_sat2(
-; CHECK-NEXT:    [[A:%.*]] = add i32 [[X:%.*]], -2
-; CHECK-NEXT:    [[C:%.*]] = icmp ugt i32 [[X]], 1
-; CHECK-NEXT:    [[R:%.*]] = select i1 [[C]], i32 [[A]], i32 -1
-; CHECK-NEXT:    ret i32 [[R]]
+; CHECK-NEXT:    [[X:%.*]] = call i32 @llvm.umax.i32(i32 [[X1:%.*]], i32 1)
+; CHECK-NEXT:    [[A:%.*]] = add i32 [[X]], -2
+; CHECK-NEXT:    ret i32 [[A]]
 ;
   %a = add i32 %x, -2
   %c = icmp ugt i32 %x, 1
diff --git a/llvm/test/Transforms/InstCombine/select.ll b/llvm/test/Transforms/InstCombine/select.ll
index a3221d7388b8fa..82c079d681284d 100644
--- a/llvm/test/Transforms/InstCombine/select.ll
+++ b/llvm/test/Transforms/InstCombine/select.ll
@@ -2989,10 +2989,9 @@ define i8 @select_replacement_loop3(i32 noundef %x) {
 
 define i16 @select_replacement_loop4(i16 noundef %p_12) {
 ; CHECK-LABEL: @select_replacement_loop4(
-; CHECK-NEXT:    [[AND1:%.*]] = and i16 [[P_12:%.*]], 1
-; CHECK-NEXT:    [[CMP21:%.*]] = icmp ult i16 [[P_12]], 2
-; CHECK-NEXT:    [[AND3:%.*]] = select i1 [[CMP21]], i16 [[AND1]], i16 0
-; CHECK-NEXT:    ret i16 [[AND3]]
+; CHECK-NEXT:    [[P_12:%.*]] = call i16 @llvm.umin.i16(i16 [[P_13:%.*]], i16 2)
+; CHECK-NEXT:    [[AND1:%.*]] = and i16 [[P_12]], 1
+; CHECK-NEXT:    ret i16 [[AND1]]
 ;
   %cmp1 = icmp ult i16 %p_12, 2
   %and1 = and i16 %p_12, 1
diff --git a/llvm/test/Transforms/InstCombine/unsigned_saturated_sub.ll b/llvm/test/Transforms/InstCombine/unsigned_saturated_sub.ll
index 1509a42872922a..15fe84369d3a0a 100644
--- a/llvm/test/Transforms/InstCombine/unsigned_saturated_sub.ll
+++ b/llvm/test/Transforms/InstCombine/unsigned_saturated_sub.ll
@@ -376,10 +376,9 @@ define i32 @max_sub_ugt_c10(i32 %a) {
 
 define i32 @max_sub_ugt_c910(i32 %a) {
 ; CHECK-LABEL: @max_sub_ugt_c910(
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i32 [[A:%.*]], 9
+; CHECK-NEXT:    [[A:%.*]] = call i32 @llvm.umax.i32(i32 [[A1:%.*]], i32 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:    ret i32 [[SUB]]
 ;
   %cmp = icmp ugt i32 %a, 9
   %sub = add i32 %a, -10
@@ -412,10 +411,9 @@ define i32 @max_sub_ugt_c0(i32 %a) {
 
 define i32 @max_sub_ugt_cmiss(i32 %a) {
 ; CHECK-LABEL: @max_sub_ugt_cmiss(
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i32 [[A:%.*]], 1
+; CHECK-NEXT:    [[A:%.*]] = call i32 @llvm.umax.i32(i32 [[A1:%.*]], i32 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:    ret i32 [[SUB]]
 ;
   %cmp = icmp ugt i32 %a, 1
   %sub = add i32 %a, -2
@@ -479,9 +477,8 @@ define i32 @max_sub_ult_c2_oneusesub(i32 %a) {
 
 define i32 @max_sub_ult_c32(i32 %a) {
 ; CHECK-LABEL: @max_sub_ult_c32(
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[A:%.*]], 3
-; CHECK-NEXT:    [[SUB:%.*]] = add i32 [[A]], -2
-; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i32 [[SUB]], i32 0
+; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @llvm.umin.i32(i32 [[A:%.*]], i32 2)
+; CHECK-NEXT:    [[SEL:%.*]] = add nsw i32 [[TMP1]], -2
 ; CHECK-NEXT:    ret i32 [[SEL]]
 ;
   %cmp = icmp ult i32 %a, 3
@@ -492,9 +489,8 @@ define i32 @max_sub_ult_c32(i32 %a) {
 
 define i32 @max_sub_ugt_c32(i32 %a) {
 ; CHECK-LABEL: @max_sub_ugt_c32(
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[A:%.*]], 3
-; CHECK-NEXT:    [[SUB:%.*]] = add i32 [[A]], -2
-; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i32 [[SUB]], i32 0
+; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @llvm.umin.i32(i32 [[A:%.*]], i32 2)
+; CHECK-NEXT:    [[SEL:%.*]] = add nsw i32 [[TMP1]], -2
 ; CHECK-NEXT:    ret i32 [[SEL]]
 ;
   %cmp = icmp ugt i32 3, %a
@@ -505,9 +501,8 @@ define i32 @max_sub_ugt_c32(i32 %a) {
 
 define i32 @max_sub_uge_c32(i32 %a) {
 ; CHECK-LABEL: @max_sub_uge_c32(
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[A:%.*]], 3
-; CHECK-NEXT:    [[SUB:%.*]] = add i32 [[A]], -2
-; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i32 [[SUB]], i32 0
+; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @llvm.umin.i32(i32 [[A:%.*]], i32 2)
+; CHECK-NEXT:    [[SEL:%.*]] = add nsw i32 [[TMP1]], -2
 ; CHECK-NEXT:    ret i32 [[SEL]]
 ;
   %cmp = icmp uge i32 2, %a



More information about the cfe-commits mailing list