[llvm] d7c8296 - [InstCombine][AArch64] Combine ORRs with logical umin ops (#213651)

via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 5 06:11:48 PDT 2026


Author: Matthew Devereau
Date: 2026-08-05T14:11:43+01:00
New Revision: d7c82962c35b906dff332c4efbd9c30100b008fb

URL: https://github.com/llvm/llvm-project/commit/d7c82962c35b906dff332c4efbd9c30100b008fb
DIFF: https://github.com/llvm/llvm-project/commit/d7c82962c35b906dff332c4efbd9c30100b008fb.diff

LOG: [InstCombine][AArch64] Combine ORRs with logical umin ops (#213651)

Combine:
  orr(umin(A, 1), umin(B, 1)) -> umin(orr(A, B), 1)

To remove a redundant UMin. This pattern has been observed with
reduction chains of multiple ORRs of UMin(x, 1), where only one final
UMin(x, 1) is necessary for truncation.

Added: 
    llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-opts-orr.ll

Modified: 
    llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
index def801b312dfa..ead9853f1da47 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
@@ -3392,6 +3392,26 @@ static std::optional<Instruction *> instCombineSVEUMin(InstCombiner &IC,
   return std::nullopt;
 }
 
+static std::optional<Instruction *> instCombineSVEOrr(InstCombiner &IC,
+                                                      IntrinsicInst &II) {
+  // orr(umin(A, 1), umin(B, 1)) -> umin(orr(A, B), 1)
+  constexpr Intrinsic::ID UMinID = Intrinsic::aarch64_sve_umin_u;
+  Value *Pg = II.getOperand(0);
+
+  Value *A, *B;
+  if (!match(II.getOperand(1), m_OneUse(m_Intrinsic<UMinID>(
+                                   m_Specific(Pg), m_Value(A), m_One()))) ||
+      !match(II.getOperand(2), m_OneUse(m_Intrinsic<UMinID>(
+                                   m_Specific(Pg), m_Value(B), m_One()))))
+    return std::nullopt;
+
+  Value *NewOrr = IC.Builder.CreateIntrinsic(Intrinsic::aarch64_sve_orr_u,
+                                             II.getType(), {Pg, A, B});
+  Value *NewUMin = IC.Builder.CreateIntrinsic(
+      UMinID, II.getType(), {Pg, NewOrr, ConstantInt::get(II.getType(), 1)});
+  return IC.replaceInstUsesWith(II, NewUMin);
+}
+
 std::optional<Instruction *>
 AArch64TTIImpl::instCombineIntrinsic(InstCombiner &IC,
                                      IntrinsicInst &II) const {
@@ -3513,6 +3533,8 @@ AArch64TTIImpl::instCombineIntrinsic(InstCombiner &IC,
     return instCombineInStreamingMode(IC, II);
   case Intrinsic::aarch64_sve_umin_u:
     return instCombineSVEUMin(IC, II);
+  case Intrinsic::aarch64_sve_orr_u:
+    return instCombineSVEOrr(IC, II);
   }
 
   return std::nullopt;

diff  --git a/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-opts-orr.ll b/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-opts-orr.ll
new file mode 100644
index 0000000000000..53a62518e21ec
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-opts-orr.ll
@@ -0,0 +1,107 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt -S -passes=instcombine < %s | FileCheck %s
+
+target triple = "aarch64-unknown-linux-gnu"
+
+define <vscale x 16 x i8> @logical_or_reduction(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a, <vscale x 16 x i8> %b) #0 {
+; CHECK-LABEL: define <vscale x 16 x i8> @logical_or_reduction(
+; CHECK-SAME: <vscale x 16 x i1> [[PG:%.*]], <vscale x 16 x i8> [[A:%.*]], <vscale x 16 x i8> [[B:%.*]]) #[[ATTR0:[0-9]+]] {
+; CHECK-NEXT:    [[TMP1:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.orr.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[A]], <vscale x 16 x i8> [[B]])
+; CHECK-NEXT:    [[TMP14:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[TMP1]], <vscale x 16 x i8> splat (i8 1))
+; CHECK-NEXT:    ret <vscale x 16 x i8> [[TMP14]]
+;
+  %a.bool = tail call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a, <vscale x 16 x i8> splat (i8 1))
+  %b.bool = tail call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %b, <vscale x 16 x i8> splat (i8 1))
+  %ab.bool = tail call <vscale x 16 x i8> @llvm.aarch64.sve.orr.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a.bool, <vscale x 16 x i8> %b.bool)
+  ret <vscale x 16 x i8> %ab.bool
+}
+
+define <vscale x 16 x i8> @no_combine_lhs_not_one(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a, <vscale x 16 x i8> %b) #0 {
+; CHECK-LABEL: define <vscale x 16 x i8> @no_combine_lhs_not_one(
+; CHECK-SAME: <vscale x 16 x i1> [[PG:%.*]], <vscale x 16 x i8> [[A:%.*]], <vscale x 16 x i8> [[B:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[A_BOOL:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[A]], <vscale x 16 x i8> splat (i8 2))
+; CHECK-NEXT:    [[B_BOOL:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[B]], <vscale x 16 x i8> splat (i8 1))
+; CHECK-NEXT:    [[RES:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.orr.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[A_BOOL]], <vscale x 16 x i8> [[B_BOOL]])
+; CHECK-NEXT:    ret <vscale x 16 x i8> [[RES]]
+;
+  %a.bool = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a, <vscale x 16 x i8> splat (i8 2))
+  %b.bool = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %b, <vscale x 16 x i8> splat (i8 1))
+  %res = call <vscale x 16 x i8> @llvm.aarch64.sve.orr.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a.bool, <vscale x 16 x i8> %b.bool)
+  ret <vscale x 16 x i8> %res
+}
+
+define <vscale x 16 x i8> @no_combine_rhs_not_one(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a, <vscale x 16 x i8> %b) #0 {
+; CHECK-LABEL: define <vscale x 16 x i8> @no_combine_rhs_not_one(
+; CHECK-SAME: <vscale x 16 x i1> [[PG:%.*]], <vscale x 16 x i8> [[A:%.*]], <vscale x 16 x i8> [[B:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[A_BOOL:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[A]], <vscale x 16 x i8> splat (i8 1))
+; CHECK-NEXT:    [[B_BOOL:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[B]], <vscale x 16 x i8> splat (i8 2))
+; CHECK-NEXT:    [[RES:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.orr.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[A_BOOL]], <vscale x 16 x i8> [[B_BOOL]])
+; CHECK-NEXT:    ret <vscale x 16 x i8> [[RES]]
+;
+  %a.bool = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a, <vscale x 16 x i8> splat (i8 1))
+  %b.bool = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %b, <vscale x 16 x i8> splat (i8 2))
+  %res = call <vscale x 16 x i8> @llvm.aarch64.sve.orr.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a.bool, <vscale x 16 x i8> %b.bool)
+  ret <vscale x 16 x i8> %res
+}
+
+define <vscale x 16 x i8> @no_combine_lhs_predicate_mismatch(<vscale x 16 x i1> %pg, <vscale x 16 x i1> %other.pg, <vscale x 16 x i8> %a, <vscale x 16 x i8> %b) #0 {
+; CHECK-LABEL: define <vscale x 16 x i8> @no_combine_lhs_predicate_mismatch(
+; CHECK-SAME: <vscale x 16 x i1> [[PG:%.*]], <vscale x 16 x i1> [[OTHER_PG:%.*]], <vscale x 16 x i8> [[A:%.*]], <vscale x 16 x i8> [[B:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[A_BOOL:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[OTHER_PG]], <vscale x 16 x i8> [[A]], <vscale x 16 x i8> splat (i8 1))
+; CHECK-NEXT:    [[B_BOOL:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[B]], <vscale x 16 x i8> splat (i8 1))
+; CHECK-NEXT:    [[RES:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.orr.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[A_BOOL]], <vscale x 16 x i8> [[B_BOOL]])
+; CHECK-NEXT:    ret <vscale x 16 x i8> [[RES]]
+;
+  %a.bool = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %other.pg, <vscale x 16 x i8> %a, <vscale x 16 x i8> splat (i8 1))
+  %b.bool = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %b, <vscale x 16 x i8> splat (i8 1))
+  %res = call <vscale x 16 x i8> @llvm.aarch64.sve.orr.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a.bool, <vscale x 16 x i8> %b.bool)
+  ret <vscale x 16 x i8> %res
+}
+
+define <vscale x 16 x i8> @no_combine_rhs_predicate_mismatch(<vscale x 16 x i1> %pg, <vscale x 16 x i1> %other.pg, <vscale x 16 x i8> %a, <vscale x 16 x i8> %b) #0 {
+; CHECK-LABEL: define <vscale x 16 x i8> @no_combine_rhs_predicate_mismatch(
+; CHECK-SAME: <vscale x 16 x i1> [[PG:%.*]], <vscale x 16 x i1> [[OTHER_PG:%.*]], <vscale x 16 x i8> [[A:%.*]], <vscale x 16 x i8> [[B:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[A_BOOL:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[A]], <vscale x 16 x i8> splat (i8 1))
+; CHECK-NEXT:    [[B_BOOL:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[OTHER_PG]], <vscale x 16 x i8> [[B]], <vscale x 16 x i8> splat (i8 1))
+; CHECK-NEXT:    [[RES:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.orr.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[A_BOOL]], <vscale x 16 x i8> [[B_BOOL]])
+; CHECK-NEXT:    ret <vscale x 16 x i8> [[RES]]
+;
+  %a.bool = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a, <vscale x 16 x i8> splat (i8 1))
+  %b.bool = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %other.pg, <vscale x 16 x i8> %b, <vscale x 16 x i8> splat (i8 1))
+  %res = call <vscale x 16 x i8> @llvm.aarch64.sve.orr.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a.bool, <vscale x 16 x i8> %b.bool)
+  ret <vscale x 16 x i8> %res
+}
+
+define <vscale x 16 x i8> @combine_lhs_umin_multiple_uses(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a, <vscale x 16 x i8> %b) #0 {
+; CHECK-LABEL: define <vscale x 16 x i8> @combine_lhs_umin_multiple_uses(
+; CHECK-SAME: <vscale x 16 x i1> [[PG:%.*]], <vscale x 16 x i8> [[A:%.*]], <vscale x 16 x i8> [[B:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[A_BOOL:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[A]], <vscale x 16 x i8> splat (i8 1))
+; CHECK-NEXT:    [[B_BOOL:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[B]], <vscale x 16 x i8> splat (i8 1))
+; CHECK-NEXT:    [[RES:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.orr.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[A_BOOL]], <vscale x 16 x i8> [[B_BOOL]])
+; CHECK-NEXT:    call void (...) @llvm.fake.use(<vscale x 16 x i8> [[A_BOOL]])
+; CHECK-NEXT:    ret <vscale x 16 x i8> [[RES]]
+;
+  %a.bool = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a, <vscale x 16 x i8> splat (i8 1))
+  %b.bool = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %b, <vscale x 16 x i8> splat (i8 1))
+  %res = call <vscale x 16 x i8> @llvm.aarch64.sve.orr.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a.bool, <vscale x 16 x i8> %b.bool)
+  call void (...) @llvm.fake.use(<vscale x 16 x i8> %a.bool)
+  ret <vscale x 16 x i8> %res
+}
+
+define <vscale x 16 x i8> @combine_rhs_umin_multiple_uses(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a, <vscale x 16 x i8> %b) #0 {
+; CHECK-LABEL: define <vscale x 16 x i8> @combine_rhs_umin_multiple_uses(
+; CHECK-SAME: <vscale x 16 x i1> [[PG:%.*]], <vscale x 16 x i8> [[A:%.*]], <vscale x 16 x i8> [[B:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[A_BOOL:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[A]], <vscale x 16 x i8> splat (i8 1))
+; CHECK-NEXT:    [[B_BOOL:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[B]], <vscale x 16 x i8> splat (i8 1))
+; CHECK-NEXT:    [[RES:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.orr.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[A_BOOL]], <vscale x 16 x i8> [[B_BOOL]])
+; CHECK-NEXT:    call void (...) @llvm.fake.use(<vscale x 16 x i8> [[B_BOOL]])
+; CHECK-NEXT:    ret <vscale x 16 x i8> [[RES]]
+;
+  %a.bool = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a, <vscale x 16 x i8> splat (i8 1))
+  %b.bool = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %b, <vscale x 16 x i8> splat (i8 1))
+  %res = call <vscale x 16 x i8> @llvm.aarch64.sve.orr.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a.bool, <vscale x 16 x i8> %b.bool)
+  call void (...) @llvm.fake.use(<vscale x 16 x i8> %b.bool)
+  ret <vscale x 16 x i8> %res
+}
+
+attributes #0 = { "target-features"="+sve" }


        


More information about the llvm-commits mailing list