[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