[llvm] [InstCombine] Fold and (or (shr (sub C, X), ShAmt), X), C --> umin(X, C) (PR #212798)

Marina Taylor via llvm-commits llvm-commits at lists.llvm.org
Wed Jul 29 08:37:49 PDT 2026


https://github.com/citymarina created https://github.com/llvm/llvm-project/pull/212798

This pattern was seen in some downstream workloads.

https://alive2.llvm.org/ce/z/_hrkqz

Assisted-by: claude

>From 10b689959a9f4a065204d500652e9e73641b6c3e Mon Sep 17 00:00:00 2001
From: Marina Taylor <marina_taylor at apple.com>
Date: Thu, 11 Jun 2026 14:43:17 +0100
Subject: [PATCH 1/2] precommit tests

---
 .../InstCombine/and-or-shr-sub-umin.ll        | 342 ++++++++++++++++++
 1 file changed, 342 insertions(+)
 create mode 100644 llvm/test/Transforms/InstCombine/and-or-shr-sub-umin.ll

diff --git a/llvm/test/Transforms/InstCombine/and-or-shr-sub-umin.ll b/llvm/test/Transforms/InstCombine/and-or-shr-sub-umin.ll
new file mode 100644
index 0000000000000..bd042b46c4abb
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/and-or-shr-sub-umin.ll
@@ -0,0 +1,342 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+; Fold:
+;   (or (shr (sub C, X), ShAmt), X) & C  -->  umin(X, C)
+; where C = (1<<S)-1, S u<= ShAmt, ShAmt + S u<= BW, and X u< 1<<ShAmt.
+
+; Positive cases
+
+; Baseline: i32, C = 255, ShAmt = 23.
+define i32 @umin_i32_lshr(i32 range(i32 0, 8388608) %x) {
+; CHECK-LABEL: define i32 @umin_i32_lshr(
+; CHECK-SAME: i32 range(i32 0, 8388608) [[X:%.*]]) {
+; CHECK-NEXT:    [[SUB:%.*]] = sub nsw i32 255, [[X]]
+; CHECK-NEXT:    [[SHR:%.*]] = lshr i32 [[SUB]], 23
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[SHR]], [[X]]
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[OR]], 255
+; CHECK-NEXT:    ret i32 [[AND]]
+;
+  %sub = sub i32 255, %x
+  %shr = lshr i32 %sub, 23
+  %or = or i32 %shr, %x
+  %and = and i32 %or, 255
+  ret i32 %and
+}
+
+; ashr form should also fold (precondition makes lshr/ashr equivalent).
+define i32 @umin_i32_ashr(i32 range(i32 0, 8388608) %x) {
+; CHECK-LABEL: define i32 @umin_i32_ashr(
+; CHECK-SAME: i32 range(i32 0, 8388608) [[X:%.*]]) {
+; CHECK-NEXT:    [[SUB:%.*]] = sub nsw i32 255, [[X]]
+; CHECK-NEXT:    [[SHR:%.*]] = lshr i32 [[SUB]], 23
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[SHR]], [[X]]
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[OR]], 255
+; CHECK-NEXT:    ret i32 [[AND]]
+;
+  %sub = sub i32 255, %x
+  %shr = ashr i32 %sub, 23
+  %or = or i32 %shr, %x
+  %and = and i32 %or, 255
+  ret i32 %and
+}
+
+; Pattern with the `or` commuted.
+define i32 @umin_i32_or_commuted(i32 range(i32 0, 8388608) %x) {
+; CHECK-LABEL: define i32 @umin_i32_or_commuted(
+; CHECK-SAME: i32 range(i32 0, 8388608) [[X:%.*]]) {
+; CHECK-NEXT:    [[SUB:%.*]] = sub nsw i32 255, [[X]]
+; CHECK-NEXT:    [[SHR:%.*]] = lshr i32 [[SUB]], 23
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[X]], [[SHR]]
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[OR]], 255
+; CHECK-NEXT:    ret i32 [[AND]]
+;
+  %sub = sub i32 255, %x
+  %shr = lshr i32 %sub, 23
+  %or = or i32 %x, %shr
+  %and = and i32 %or, 255
+  ret i32 %and
+}
+
+; i8, C = 7, ShAmt = 4.
+define i8 @umin_i8(i8 range(i8 0, 16) %x) {
+; CHECK-LABEL: define i8 @umin_i8(
+; CHECK-SAME: i8 range(i8 0, 16) [[X:%.*]]) {
+; CHECK-NEXT:    [[SUB:%.*]] = sub nsw i8 7, [[X]]
+; CHECK-NEXT:    [[SHR:%.*]] = lshr i8 [[SUB]], 4
+; CHECK-NEXT:    [[OR:%.*]] = or i8 [[SHR]], [[X]]
+; CHECK-NEXT:    [[AND:%.*]] = and i8 [[OR]], 7
+; CHECK-NEXT:    ret i8 [[AND]]
+;
+  %sub = sub i8 7, %x
+  %shr = lshr i8 %sub, 4
+  %or = or i8 %shr, %x
+  %and = and i8 %or, 7
+  ret i8 %and
+}
+
+; Tight boundary on S=15, with ShAmt=16.
+define i32 @umin_tight_boundary(i32 range(i32 0, 65536) %x) {
+; CHECK-LABEL: define i32 @umin_tight_boundary(
+; CHECK-SAME: i32 range(i32 0, 65536) [[X:%.*]]) {
+; CHECK-NEXT:    [[SUB:%.*]] = sub nsw i32 32767, [[X]]
+; CHECK-NEXT:    [[SHR:%.*]] = lshr i32 [[SUB]], 16
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[SHR]], [[X]]
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[OR]], 32767
+; CHECK-NEXT:    ret i32 [[AND]]
+;
+  %sub = sub i32 32767, %x
+  %shr = lshr i32 %sub, 16
+  %or = or i32 %shr, %x
+  %and = and i32 %or, 32767
+  ret i32 %and
+}
+
+; Boundary where the X u< 1<<ShAmt bound coincides with C+1 (i33, S=16,
+; ShAmt=16): X u< 2^16 == C+1 means X u<= C always, so umin(X, C) collapses
+; to X. Validates the fold's boundary behavior even though the umin is trivial.
+define i33 @umin_tight_boundary_i33(i33 range(i33 0, 65536) %x) {
+; CHECK-LABEL: define i33 @umin_tight_boundary_i33(
+; CHECK-SAME: i33 range(i33 0, 65536) [[X:%.*]]) {
+; CHECK-NEXT:    ret i33 [[X]]
+;
+  %sub = sub i33 65535, %x
+  %shr = lshr i33 %sub, 16
+  %or = or i33 %shr, %x
+  %and = and i33 %or, 65535
+  ret i33 %and
+}
+
+; One step below the tight boundary on an odd BW (i33, S=15, ShAmt=17):
+; precondition X u< 2^17 admits X u> C, so umin(X, C) is non-trivial and the
+; fold produces a real umin call.
+define i33 @umin_near_tight_i33(i33 range(i33 0, 131072) %x) {
+; CHECK-LABEL: define i33 @umin_near_tight_i33(
+; CHECK-SAME: i33 range(i33 0, 131072) [[X:%.*]]) {
+; CHECK-NEXT:    [[SUB:%.*]] = sub nsw i33 32767, [[X]]
+; CHECK-NEXT:    [[SHR:%.*]] = lshr i33 [[SUB]], 17
+; CHECK-NEXT:    [[OR:%.*]] = or i33 [[SHR]], [[X]]
+; CHECK-NEXT:    [[AND:%.*]] = and i33 [[OR]], 32767
+; CHECK-NEXT:    ret i33 [[AND]]
+;
+  %sub = sub i33 32767, %x
+  %shr = lshr i33 %sub, 17
+  %or = or i33 %shr, %x
+  %and = and i33 %or, 32767
+  ret i33 %and
+}
+
+; Vector splat.
+define <2 x i32> @umin_v2i32(<2 x i32> range(i32 0, 8388608) %x) {
+; CHECK-LABEL: define <2 x i32> @umin_v2i32(
+; CHECK-SAME: <2 x i32> range(i32 0, 8388608) [[X:%.*]]) {
+; CHECK-NEXT:    [[SUB:%.*]] = sub nsw <2 x i32> splat (i32 255), [[X]]
+; CHECK-NEXT:    [[SHR:%.*]] = lshr <2 x i32> [[SUB]], splat (i32 23)
+; CHECK-NEXT:    [[OR:%.*]] = or <2 x i32> [[SHR]], [[X]]
+; CHECK-NEXT:    [[AND:%.*]] = and <2 x i32> [[OR]], splat (i32 255)
+; CHECK-NEXT:    ret <2 x i32> [[AND]]
+;
+  %sub = sub <2 x i32> splat (i32 255), %x
+  %shr = lshr <2 x i32> %sub, splat (i32 23)
+  %or = or <2 x i32> %shr, %x
+  %and = and <2 x i32> %or, splat (i32 255)
+  ret <2 x i32> %and
+}
+
+; Generalized ShAmt: C=255 (S=8) but ShAmt=20, which is < BW-S-1 = 23.
+define i32 @umin_i32_shamt_below_max(i32 range(i32 0, 1048576) %x) {
+; CHECK-LABEL: define i32 @umin_i32_shamt_below_max(
+; CHECK-SAME: i32 range(i32 0, 1048576) [[X:%.*]]) {
+; CHECK-NEXT:    [[SUB:%.*]] = sub nsw i32 255, [[X]]
+; CHECK-NEXT:    [[SHR:%.*]] = lshr i32 [[SUB]], 20
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[SHR]], [[X]]
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[OR]], 255
+; CHECK-NEXT:    ret i32 [[AND]]
+;
+  %sub = sub i32 255, %x
+  %shr = lshr i32 %sub, 20
+  %or = or i32 %shr, %x
+  %and = and i32 %or, 255
+  ret i32 %and
+}
+
+; Negative cases
+
+; S > ShAmt: C=0xFFFF (S=16), ShAmt=15, so S u<= ShAmt fails. sub(C, X) can be
+; as large as C = 0xFFFF >= 1<<ShAmt, so the shift is nonzero for X u<= C and
+; the "below-mask" case produces X | 1 instead of X.
+define i32 @neg_past_boundary(i32 range(i32 0, 32768) %x) {
+; CHECK-LABEL: define i32 @neg_past_boundary(
+; CHECK-SAME: i32 range(i32 0, 32768) [[X:%.*]]) {
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[X]], 1
+; CHECK-NEXT:    ret i32 [[OR]]
+;
+  %sub = sub i32 65535, %x
+  %shr = lshr i32 %sub, 15
+  %or = or i32 %shr, %x
+  %and = and i32 %or, 65535
+  ret i32 %and
+}
+
+; X not known to be bounded.
+define i32 @neg_unbounded(i32 %x) {
+; CHECK-LABEL: define i32 @neg_unbounded(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT:    [[SUB:%.*]] = sub i32 255, [[X]]
+; CHECK-NEXT:    [[SHR:%.*]] = lshr i32 [[SUB]], 23
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[SHR]], [[X]]
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[OR]], 255
+; CHECK-NEXT:    ret i32 [[AND]]
+;
+  %sub = sub i32 255, %x
+  %shr = lshr i32 %sub, 23
+  %or = or i32 %shr, %x
+  %and = and i32 %or, 255
+  ret i32 %and
+}
+
+; ShAmt=22 is structurally fine (S=8 <= 22, 22+8 <= 32), and with X u< 2^22
+; the fold fires.  This pins the ShAmt-coupled precondition: the bound on X is
+; 1<<ShAmt, not a fixed quantity.
+define i32 @umin_i32_shamt22_in_range(i32 range(i32 0, 4194304) %x) {
+; CHECK-LABEL: define i32 @umin_i32_shamt22_in_range(
+; CHECK-SAME: i32 range(i32 0, 4194304) [[X:%.*]]) {
+; CHECK-NEXT:    [[SUB:%.*]] = sub nsw i32 255, [[X]]
+; CHECK-NEXT:    [[SHR:%.*]] = lshr i32 [[SUB]], 22
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[SHR]], [[X]]
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[OR]], 255
+; CHECK-NEXT:    ret i32 [[AND]]
+;
+  %sub = sub i32 255, %x
+  %shr = lshr i32 %sub, 22
+  %or = or i32 %shr, %x
+  %and = and i32 %or, 255
+  ret i32 %and
+}
+
+; Same ShAmt=22, but X is only known u< 2^23, so X u< 1<<ShAmt = 2^22 fails and
+; the fold is correctly rejected.
+define i32 @neg_range_exceeds_shamt(i32 range(i32 0, 8388608) %x) {
+; CHECK-LABEL: define i32 @neg_range_exceeds_shamt(
+; CHECK-SAME: i32 range(i32 0, 8388608) [[X:%.*]]) {
+; CHECK-NEXT:    [[SUB:%.*]] = sub nsw i32 255, [[X]]
+; CHECK-NEXT:    [[SHR:%.*]] = lshr i32 [[SUB]], 22
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[SHR]], [[X]]
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[OR]], 255
+; CHECK-NEXT:    ret i32 [[AND]]
+;
+  %sub = sub i32 255, %x
+  %shr = lshr i32 %sub, 22
+  %or = or i32 %shr, %x
+  %and = and i32 %or, 255
+  ret i32 %and
+}
+
+; ShAmt + S > BW: C=255 (S=8), ShAmt=25, so 25+8 = 33 > 32.  Even with X u< 2^25
+; the borrow's all-ones run does not reach bit S-1, so the fold is invalid.
+define i32 @neg_shamt_plus_s_exceeds_bw(i32 range(i32 0, 33554432) %x) {
+; CHECK-LABEL: define i32 @neg_shamt_plus_s_exceeds_bw(
+; CHECK-SAME: i32 range(i32 0, 33554432) [[X:%.*]]) {
+; CHECK-NEXT:    [[SUB:%.*]] = sub nsw i32 255, [[X]]
+; CHECK-NEXT:    [[SHR:%.*]] = lshr i32 [[SUB]], 25
+; CHECK-NEXT:    [[X_MASKED:%.*]] = and i32 [[X]], 255
+; CHECK-NEXT:    [[AND:%.*]] = or i32 [[SHR]], [[X_MASKED]]
+; CHECK-NEXT:    ret i32 [[AND]]
+;
+  %sub = sub i32 255, %x
+  %shr = lshr i32 %sub, 25
+  %or = or i32 %shr, %x
+  %and = and i32 %or, 255
+  ret i32 %and
+}
+
+; AND constant differs from SUB constant.
+define i32 @neg_mismatched_constants(i32 range(i32 0, 8388608) %x) {
+; CHECK-LABEL: define i32 @neg_mismatched_constants(
+; CHECK-SAME: i32 range(i32 0, 8388608) [[X:%.*]]) {
+; CHECK-NEXT:    [[SUB:%.*]] = sub nsw i32 127, [[X]]
+; CHECK-NEXT:    [[SHR:%.*]] = lshr i32 [[SUB]], 23
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[SHR]], [[X]]
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[OR]], 255
+; CHECK-NEXT:    ret i32 [[AND]]
+;
+  %sub = sub i32 127, %x
+  %shr = lshr i32 %sub, 23
+  %or = or i32 %shr, %x
+  %and = and i32 %or, 255
+  ret i32 %and
+}
+
+; C is not of the form 2^S - 1.
+define i32 @neg_non_mask(i32 range(i32 0, 8388608) %x) {
+; CHECK-LABEL: define i32 @neg_non_mask(
+; CHECK-SAME: i32 range(i32 0, 8388608) [[X:%.*]]) {
+; CHECK-NEXT:    [[SUB:%.*]] = sub nsw i32 254, [[X]]
+; CHECK-NEXT:    [[SHR:%.*]] = lshr i32 [[SUB]], 23
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[SHR]], [[X]]
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[OR]], 254
+; CHECK-NEXT:    ret i32 [[AND]]
+;
+  %sub = sub i32 254, %x
+  %shr = lshr i32 %sub, 23
+  %or = or i32 %shr, %x
+  %and = and i32 %or, 254
+  ret i32 %and
+}
+
+; Multi-use on the `sub`: fold is not profitable.
+define i32 @neg_multiuse_sub(i32 range(i32 0, 8388608) %x, ptr %sink) {
+; CHECK-LABEL: define i32 @neg_multiuse_sub(
+; CHECK-SAME: i32 range(i32 0, 8388608) [[X:%.*]], ptr [[SINK:%.*]]) {
+; CHECK-NEXT:    [[SUB:%.*]] = sub nsw i32 255, [[X]]
+; CHECK-NEXT:    store i32 [[SUB]], ptr [[SINK]], align 4
+; CHECK-NEXT:    [[SHR:%.*]] = lshr i32 [[SUB]], 23
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[SHR]], [[X]]
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[OR]], 255
+; CHECK-NEXT:    ret i32 [[AND]]
+;
+  %sub = sub i32 255, %x
+  store i32 %sub, ptr %sink
+  %shr = lshr i32 %sub, 23
+  %or = or i32 %shr, %x
+  %and = and i32 %or, 255
+  ret i32 %and
+}
+
+; Multi-use on the `shr`: fold is not profitable.
+define i32 @neg_multiuse_shr(i32 range(i32 0, 8388608) %x, ptr %sink) {
+; CHECK-LABEL: define i32 @neg_multiuse_shr(
+; CHECK-SAME: i32 range(i32 0, 8388608) [[X:%.*]], ptr [[SINK:%.*]]) {
+; CHECK-NEXT:    [[SUB:%.*]] = sub nsw i32 255, [[X]]
+; CHECK-NEXT:    [[SHR:%.*]] = lshr i32 [[SUB]], 23
+; CHECK-NEXT:    store i32 [[SHR]], ptr [[SINK]], align 4
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[SHR]], [[X]]
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[OR]], 255
+; CHECK-NEXT:    ret i32 [[AND]]
+;
+  %sub = sub i32 255, %x
+  %shr = lshr i32 %sub, 23
+  store i32 %shr, ptr %sink
+  %or = or i32 %shr, %x
+  %and = and i32 %or, 255
+  ret i32 %and
+}
+
+; Multi-use on the `or`: fold is not profitable.
+define i32 @neg_multiuse_or(i32 range(i32 0, 8388608) %x, ptr %sink) {
+; CHECK-LABEL: define i32 @neg_multiuse_or(
+; CHECK-SAME: i32 range(i32 0, 8388608) [[X:%.*]], ptr [[SINK:%.*]]) {
+; CHECK-NEXT:    [[SUB:%.*]] = sub nsw i32 255, [[X]]
+; CHECK-NEXT:    [[SHR:%.*]] = lshr i32 [[SUB]], 23
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[SHR]], [[X]]
+; CHECK-NEXT:    store i32 [[OR]], ptr [[SINK]], align 4
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[OR]], 255
+; CHECK-NEXT:    ret i32 [[AND]]
+;
+  %sub = sub i32 255, %x
+  %shr = lshr i32 %sub, 23
+  %or = or i32 %shr, %x
+  store i32 %or, ptr %sink
+  %and = and i32 %or, 255
+  ret i32 %and
+}

>From 458a965c3ec0cf734154b2e53f04f00a2ea24a6b Mon Sep 17 00:00:00 2001
From: Marina Taylor <marina_taylor at apple.com>
Date: Mon, 27 Jul 2026 14:33:07 +0100
Subject: [PATCH 2/2] [InstCombine] Fold and (or (shr (sub C, X), ShAmt), X), C
  -->  umin(X, C)

https://alive2.llvm.org/ce/z/_hrkqz

Assisted-by: claude
---
 .../InstCombine/InstCombineAndOrXor.cpp       | 25 +++++++++++
 .../InstCombine/and-or-shr-sub-umin.ll        | 45 ++++---------------
 2 files changed, 34 insertions(+), 36 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
index b6f4a55c07e8a..2878adfcd1fef 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
@@ -2673,6 +2673,31 @@ Instruction *InstCombinerImpl::visitAnd(BinaryOperator &I) {
         }
       }
     }
+
+    // and (or (shr (sub C, X), ShAmt), X), C  -->  umin(X, C)
+    // The fold holds when all of:
+    // - C is a low-bit mask: C = (1<<S)-1
+    // - S u<= ShAmt       -- When X u<= C, sub(C, X) u< 1<<ShAmt, so shr is 0
+    // - ShAmt + S u<= BW  -- the borrow's all-ones run reaches up to bit S-1
+    // - X u< 1<<ShAmt     -- bounds X - C u< 1<<ShAmt in the X u> C case
+    // Then shr(sub(C, X), ShAmt) is 0 when X u<= C and has all of C's bits set
+    // when X u> C, so (shr | X) & C clamps X to C. The bound on X also means
+    // ashr and lshr have the same result.
+    const APInt *ShAmtC;
+    if (C->isMask() &&
+        match(Op0,
+              m_OneUse(m_c_Or(
+                  m_OneUse(m_Shr(m_OneUse(m_Sub(m_SpecificInt(*C), m_Value(X))),
+                                 m_APInt(ShAmtC))),
+                  m_Deferred(X)))) &&
+        ShAmtC->ult(Width)) {
+      unsigned S = C->popcount();
+      unsigned ShAmt = ShAmtC->getZExtValue();
+      if (S <= ShAmt && ShAmt + S <= Width &&
+          MaskedValueIsZero(X, APInt::getBitsSetFrom(Width, ShAmt), &I))
+        return replaceInstUsesWith(
+            I, Builder.CreateBinaryIntrinsic(Intrinsic::umin, X, Op1));
+    }
   }
 
   // If we are clearing the sign bit of a floating-point value, convert this to
diff --git a/llvm/test/Transforms/InstCombine/and-or-shr-sub-umin.ll b/llvm/test/Transforms/InstCombine/and-or-shr-sub-umin.ll
index bd042b46c4abb..19db76216660b 100644
--- a/llvm/test/Transforms/InstCombine/and-or-shr-sub-umin.ll
+++ b/llvm/test/Transforms/InstCombine/and-or-shr-sub-umin.ll
@@ -11,10 +11,7 @@
 define i32 @umin_i32_lshr(i32 range(i32 0, 8388608) %x) {
 ; CHECK-LABEL: define i32 @umin_i32_lshr(
 ; CHECK-SAME: i32 range(i32 0, 8388608) [[X:%.*]]) {
-; CHECK-NEXT:    [[SUB:%.*]] = sub nsw i32 255, [[X]]
-; CHECK-NEXT:    [[SHR:%.*]] = lshr i32 [[SUB]], 23
-; CHECK-NEXT:    [[OR:%.*]] = or i32 [[SHR]], [[X]]
-; CHECK-NEXT:    [[AND:%.*]] = and i32 [[OR]], 255
+; CHECK-NEXT:    [[AND:%.*]] = call i32 @llvm.umin.i32(i32 [[X]], i32 255)
 ; CHECK-NEXT:    ret i32 [[AND]]
 ;
   %sub = sub i32 255, %x
@@ -28,10 +25,7 @@ define i32 @umin_i32_lshr(i32 range(i32 0, 8388608) %x) {
 define i32 @umin_i32_ashr(i32 range(i32 0, 8388608) %x) {
 ; CHECK-LABEL: define i32 @umin_i32_ashr(
 ; CHECK-SAME: i32 range(i32 0, 8388608) [[X:%.*]]) {
-; CHECK-NEXT:    [[SUB:%.*]] = sub nsw i32 255, [[X]]
-; CHECK-NEXT:    [[SHR:%.*]] = lshr i32 [[SUB]], 23
-; CHECK-NEXT:    [[OR:%.*]] = or i32 [[SHR]], [[X]]
-; CHECK-NEXT:    [[AND:%.*]] = and i32 [[OR]], 255
+; CHECK-NEXT:    [[AND:%.*]] = call i32 @llvm.umin.i32(i32 [[X]], i32 255)
 ; CHECK-NEXT:    ret i32 [[AND]]
 ;
   %sub = sub i32 255, %x
@@ -45,10 +39,7 @@ define i32 @umin_i32_ashr(i32 range(i32 0, 8388608) %x) {
 define i32 @umin_i32_or_commuted(i32 range(i32 0, 8388608) %x) {
 ; CHECK-LABEL: define i32 @umin_i32_or_commuted(
 ; CHECK-SAME: i32 range(i32 0, 8388608) [[X:%.*]]) {
-; CHECK-NEXT:    [[SUB:%.*]] = sub nsw i32 255, [[X]]
-; CHECK-NEXT:    [[SHR:%.*]] = lshr i32 [[SUB]], 23
-; CHECK-NEXT:    [[OR:%.*]] = or i32 [[X]], [[SHR]]
-; CHECK-NEXT:    [[AND:%.*]] = and i32 [[OR]], 255
+; CHECK-NEXT:    [[AND:%.*]] = call i32 @llvm.umin.i32(i32 [[X]], i32 255)
 ; CHECK-NEXT:    ret i32 [[AND]]
 ;
   %sub = sub i32 255, %x
@@ -62,10 +53,7 @@ define i32 @umin_i32_or_commuted(i32 range(i32 0, 8388608) %x) {
 define i8 @umin_i8(i8 range(i8 0, 16) %x) {
 ; CHECK-LABEL: define i8 @umin_i8(
 ; CHECK-SAME: i8 range(i8 0, 16) [[X:%.*]]) {
-; CHECK-NEXT:    [[SUB:%.*]] = sub nsw i8 7, [[X]]
-; CHECK-NEXT:    [[SHR:%.*]] = lshr i8 [[SUB]], 4
-; CHECK-NEXT:    [[OR:%.*]] = or i8 [[SHR]], [[X]]
-; CHECK-NEXT:    [[AND:%.*]] = and i8 [[OR]], 7
+; CHECK-NEXT:    [[AND:%.*]] = call i8 @llvm.umin.i8(i8 [[X]], i8 7)
 ; CHECK-NEXT:    ret i8 [[AND]]
 ;
   %sub = sub i8 7, %x
@@ -79,10 +67,7 @@ define i8 @umin_i8(i8 range(i8 0, 16) %x) {
 define i32 @umin_tight_boundary(i32 range(i32 0, 65536) %x) {
 ; CHECK-LABEL: define i32 @umin_tight_boundary(
 ; CHECK-SAME: i32 range(i32 0, 65536) [[X:%.*]]) {
-; CHECK-NEXT:    [[SUB:%.*]] = sub nsw i32 32767, [[X]]
-; CHECK-NEXT:    [[SHR:%.*]] = lshr i32 [[SUB]], 16
-; CHECK-NEXT:    [[OR:%.*]] = or i32 [[SHR]], [[X]]
-; CHECK-NEXT:    [[AND:%.*]] = and i32 [[OR]], 32767
+; CHECK-NEXT:    [[AND:%.*]] = call i32 @llvm.umin.i32(i32 [[X]], i32 32767)
 ; CHECK-NEXT:    ret i32 [[AND]]
 ;
   %sub = sub i32 32767, %x
@@ -113,10 +98,7 @@ define i33 @umin_tight_boundary_i33(i33 range(i33 0, 65536) %x) {
 define i33 @umin_near_tight_i33(i33 range(i33 0, 131072) %x) {
 ; CHECK-LABEL: define i33 @umin_near_tight_i33(
 ; CHECK-SAME: i33 range(i33 0, 131072) [[X:%.*]]) {
-; CHECK-NEXT:    [[SUB:%.*]] = sub nsw i33 32767, [[X]]
-; CHECK-NEXT:    [[SHR:%.*]] = lshr i33 [[SUB]], 17
-; CHECK-NEXT:    [[OR:%.*]] = or i33 [[SHR]], [[X]]
-; CHECK-NEXT:    [[AND:%.*]] = and i33 [[OR]], 32767
+; CHECK-NEXT:    [[AND:%.*]] = call i33 @llvm.umin.i33(i33 [[X]], i33 32767)
 ; CHECK-NEXT:    ret i33 [[AND]]
 ;
   %sub = sub i33 32767, %x
@@ -130,10 +112,7 @@ define i33 @umin_near_tight_i33(i33 range(i33 0, 131072) %x) {
 define <2 x i32> @umin_v2i32(<2 x i32> range(i32 0, 8388608) %x) {
 ; CHECK-LABEL: define <2 x i32> @umin_v2i32(
 ; CHECK-SAME: <2 x i32> range(i32 0, 8388608) [[X:%.*]]) {
-; CHECK-NEXT:    [[SUB:%.*]] = sub nsw <2 x i32> splat (i32 255), [[X]]
-; CHECK-NEXT:    [[SHR:%.*]] = lshr <2 x i32> [[SUB]], splat (i32 23)
-; CHECK-NEXT:    [[OR:%.*]] = or <2 x i32> [[SHR]], [[X]]
-; CHECK-NEXT:    [[AND:%.*]] = and <2 x i32> [[OR]], splat (i32 255)
+; CHECK-NEXT:    [[AND:%.*]] = call <2 x i32> @llvm.umin.v2i32(<2 x i32> [[X]], <2 x i32> splat (i32 255))
 ; CHECK-NEXT:    ret <2 x i32> [[AND]]
 ;
   %sub = sub <2 x i32> splat (i32 255), %x
@@ -147,10 +126,7 @@ define <2 x i32> @umin_v2i32(<2 x i32> range(i32 0, 8388608) %x) {
 define i32 @umin_i32_shamt_below_max(i32 range(i32 0, 1048576) %x) {
 ; CHECK-LABEL: define i32 @umin_i32_shamt_below_max(
 ; CHECK-SAME: i32 range(i32 0, 1048576) [[X:%.*]]) {
-; CHECK-NEXT:    [[SUB:%.*]] = sub nsw i32 255, [[X]]
-; CHECK-NEXT:    [[SHR:%.*]] = lshr i32 [[SUB]], 20
-; CHECK-NEXT:    [[OR:%.*]] = or i32 [[SHR]], [[X]]
-; CHECK-NEXT:    [[AND:%.*]] = and i32 [[OR]], 255
+; CHECK-NEXT:    [[AND:%.*]] = call i32 @llvm.umin.i32(i32 [[X]], i32 255)
 ; CHECK-NEXT:    ret i32 [[AND]]
 ;
   %sub = sub i32 255, %x
@@ -201,10 +177,7 @@ define i32 @neg_unbounded(i32 %x) {
 define i32 @umin_i32_shamt22_in_range(i32 range(i32 0, 4194304) %x) {
 ; CHECK-LABEL: define i32 @umin_i32_shamt22_in_range(
 ; CHECK-SAME: i32 range(i32 0, 4194304) [[X:%.*]]) {
-; CHECK-NEXT:    [[SUB:%.*]] = sub nsw i32 255, [[X]]
-; CHECK-NEXT:    [[SHR:%.*]] = lshr i32 [[SUB]], 22
-; CHECK-NEXT:    [[OR:%.*]] = or i32 [[SHR]], [[X]]
-; CHECK-NEXT:    [[AND:%.*]] = and i32 [[OR]], 255
+; CHECK-NEXT:    [[AND:%.*]] = call i32 @llvm.umin.i32(i32 [[X]], i32 255)
 ; CHECK-NEXT:    ret i32 [[AND]]
 ;
   %sub = sub i32 255, %x



More information about the llvm-commits mailing list