Skip to content

[AArch64][InstCombine] Fold zext cmpne umin boolean trees#209234

Open
MDevereau wants to merge 1 commit into
llvm:mainfrom
MDevereau:umin_reduce
Open

[AArch64][InstCombine] Fold zext cmpne umin boolean trees#209234
MDevereau wants to merge 1 commit into
llvm:mainfrom
MDevereau:umin_reduce

Conversation

@MDevereau

@MDevereau MDevereau commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Fold an all-active umin tree of zext(cmpne(0, umin)) nodes:

  zext(cmpne(0, umin(zext(cmpne(0, umin(%a, %b)))
                     zext(cmpne(0, umin(%c, %d))))))
  ->
  zext(cmpne(0, umin(umin(%a, %b),
                     umin(%c, %d))))

Fold an all-active umin tree of zext(cmpne(0, umin)) nodes:

  zext(cmpne(0, umin(zext(cmpne(0, umin(%a, %b)))
                     zext(cmpne(0, umin(%c, %d))))))
  ->
  zext(cmpne(0, umin(umin(%a, %b),
                     umin(%c, %d))))
@MDevereau MDevereau marked this pull request as ready for review July 14, 2026 13:27
@MDevereau MDevereau requested a review from paulwalker-arm July 14, 2026 13:28
@llvmorg-github-actions llvmorg-github-actions Bot added backend:AArch64 llvm:instcombine Covers the InstCombine, InstSimplify and AggressiveInstCombine passes llvm:transforms labels Jul 14, 2026
@llvmorg-github-actions

llvmorg-github-actions Bot commented Jul 14, 2026

Copy link
Copy Markdown

@llvm/pr-subscribers-llvm-transforms

@llvm/pr-subscribers-backend-aarch64

Author: Matthew Devereau (MDevereau)

Changes

Fold an all-active umin tree of zext(cmpne(0, umin)) nodes:

  zext(cmpne(0, umin(zext(cmpne(0, umin(%a, %b)))
                     zext(cmpne(0, umin(%c, %d))))))
  ->
  zext(cmpne(0, umin(umin(%a, %b),
                     umin(%c, %d))))

Patch is 21.09 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/209234.diff

2 Files Affected:

  • (modified) llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp (+66)
  • (modified) llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-opts-cmpne.ll (+154)
diff --git a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
index 9e1a0960617a5..024f9efaf18f2 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
@@ -2205,6 +2205,69 @@ static std::optional<Instruction *> instCombineZExtSVECmpNE(InstCombiner &IC,
   return std::nullopt;
 }
 
+static std::optional<Instruction *> isZextedCmpneUMin(Value *V) {
+  Instruction *CmpNE;
+  if (!match(V, m_ZExt(m_Instruction(CmpNE))))
+    return std::nullopt;
+
+  Value *Pg;
+  Instruction *UMin;
+  if (!match(CmpNE, m_Intrinsic<Intrinsic::aarch64_sve_cmpne>(
+                        m_Value(Pg), m_Zero(), m_Instruction(UMin))) ||
+      !isAllActivePredicate(Pg) || V->getType() != UMin->getType())
+    return std::nullopt;
+
+  Value *UMinPg;
+  if (!match(UMin, m_Intrinsic<Intrinsic::aarch64_sve_umin_u>(
+                       m_Value(UMinPg), m_Value(), m_Value())) ||
+      !isAllActivePredicate(UMinPg))
+    return std::nullopt;
+
+  return UMin;
+}
+
+// InstCombine:
+// zext(cmpne(0, umin(zext(cmpne(0, umin(%a, %b)))
+//                    zext(cmpne(0, umin(%c, %d))))))
+// ->
+// zext(cmpne(0, umin(umin(%a, %b),
+//                    umin(%c, %d))))
+//
+// To remove redundant ZExt and CmpNE intrinsics.
+static std::optional<Instruction *>
+instCombineZExtCmpNEUMinTree(InstCombiner &IC, IntrinsicInst &II) {
+  Value *Pg = II.getOperand(0);
+  if (!isAllActivePredicate(Pg) || !II.hasOneUse())
+    return std::nullopt;
+
+  auto ZExt = cast<Instruction>(*II.user_begin());
+  auto _UMin = isZextedCmpneUMin(ZExt);
+  if (!_UMin)
+    return std::nullopt;
+  Instruction *UMin = *_UMin;
+  // Check for outer UMin single use to avoid generating an extra UMin
+  if (!UMin->hasOneUse())
+    return std::nullopt;
+
+  auto LhsUMin = isZextedCmpneUMin(UMin->getOperand(1));
+  auto RhsUMin = isZextedCmpneUMin(UMin->getOperand(2));
+  if (!LhsUMin || !RhsUMin)
+    return std::nullopt;
+
+  IC.Builder.SetInsertPoint(ZExt);
+  Type *Ty = UMin->getType();
+  Value *NewUMin = IC.Builder.CreateIntrinsic(Intrinsic::aarch64_sve_umin_u, Ty,
+                                              {Pg, *LhsUMin, *RhsUMin});
+  Value *NewCmpne =
+      IC.Builder.CreateIntrinsic(Intrinsic::aarch64_sve_cmpne, Ty,
+                                 {Pg, ConstantInt::getNullValue(Ty), NewUMin});
+  Value *NewZext = IC.Builder.CreateZExt(NewCmpne, Ty);
+
+  IC.replaceInstUsesWith(*ZExt, NewZext);
+  IC.eraseInstFromFunction(*ZExt);
+  return &II;
+}
+
 static std::optional<Instruction *> instCombineSVECmpNE(InstCombiner &IC,
                                                         IntrinsicInst &II) {
   LLVMContext &Ctx = II.getContext();
@@ -2215,6 +2278,9 @@ static std::optional<Instruction *> instCombineSVECmpNE(InstCombiner &IC,
   if (auto Res = instCombineZExtSVECmpNE(IC, II))
     return Res;
 
+  if (auto Res = instCombineZExtCmpNEUMinTree(IC, II))
+    return Res;
+
   if (!isAllActivePredicate(II.getArgOperand(0)))
     return std::nullopt;
 
diff --git a/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-opts-cmpne.ll b/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-opts-cmpne.ll
index 11e6e0089293a..a434ad086d891 100644
--- a/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-opts-cmpne.ll
+++ b/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-opts-cmpne.ll
@@ -573,6 +573,160 @@ define <vscale x 16 x i1> @dupq_b_idx(i64 %idx) #0 {
   ret <vscale x 16 x i1> %5
 }
 
+define <vscale x 16 x i8> @logical_bool_tree_i8(<vscale x 16 x i8> %a, <vscale x 16 x i8> %b, <vscale x 16 x i8> %c, <vscale x 16 x i8> %d) #0 {
+; CHECK-LABEL: define <vscale x 16 x i8> @logical_bool_tree_i8(
+; CHECK-SAME: <vscale x 16 x i8> [[A:%.*]], <vscale x 16 x i8> [[B:%.*]], <vscale x 16 x i8> [[C:%.*]], <vscale x 16 x i8> [[D:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[AB:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> [[A]], <vscale x 16 x i8> [[B]])
+; CHECK-NEXT:    [[CD:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> [[C]], <vscale x 16 x i8> [[D]])
+; CHECK-NEXT:    [[ABCD:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> [[AB]], <vscale x 16 x i8> [[CD]])
+; CHECK-NEXT:    [[ABCD_CMP:%.*]] = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpne.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> zeroinitializer, <vscale x 16 x i8> [[ABCD]])
+; CHECK-NEXT:    [[ABCD_BOOL:%.*]] = zext <vscale x 16 x i1> [[ABCD_CMP]] to <vscale x 16 x i8>
+; CHECK-NEXT:    ret <vscale x 16 x i8> [[ABCD_BOOL]]
+;
+  %ab = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> %a, <vscale x 16 x i8> %b)
+  %ab.cmp = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpne.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> zeroinitializer, <vscale x 16 x i8> %ab)
+  %ab.bool = zext <vscale x 16 x i1> %ab.cmp to <vscale x 16 x i8>
+  %cd = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> %c, <vscale x 16 x i8> %d)
+  %cd.cmp = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpne.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> zeroinitializer, <vscale x 16 x i8> %cd)
+  %cd.bool = zext <vscale x 16 x i1> %cd.cmp to <vscale x 16 x i8>
+  %abcd = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> %ab.bool, <vscale x 16 x i8> %cd.bool)
+  %abcd.cmp = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpne.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> zeroinitializer, <vscale x 16 x i8> %abcd)
+  %abcd.bool = zext <vscale x 16 x i1> %abcd.cmp to <vscale x 16 x i8>
+  ret <vscale x 16 x i8> %abcd.bool
+}
+
+define <vscale x 16 x i8> @logical_bool_tree_outer_umin_extra_use_i8(<vscale x 16 x i8> %a, <vscale x 16 x i8> %b, <vscale x 16 x i8> %c, <vscale x 16 x i8> %d) #0 {
+; CHECK-LABEL: define <vscale x 16 x i8> @logical_bool_tree_outer_umin_extra_use_i8(
+; CHECK-SAME: <vscale x 16 x i8> [[A:%.*]], <vscale x 16 x i8> [[B:%.*]], <vscale x 16 x i8> [[C:%.*]], <vscale x 16 x i8> [[D:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[AB:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> [[A]], <vscale x 16 x i8> [[B]])
+; CHECK-NEXT:    [[AB_CMP:%.*]] = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpne.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> zeroinitializer, <vscale x 16 x i8> [[AB]])
+; CHECK-NEXT:    [[AB_BOOL:%.*]] = zext <vscale x 16 x i1> [[AB_CMP]] to <vscale x 16 x i8>
+; CHECK-NEXT:    [[CD:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> [[C]], <vscale x 16 x i8> [[D]])
+; CHECK-NEXT:    [[CD_CMP:%.*]] = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpne.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> zeroinitializer, <vscale x 16 x i8> [[CD]])
+; CHECK-NEXT:    [[CD_BOOL:%.*]] = zext <vscale x 16 x i1> [[CD_CMP]] to <vscale x 16 x i8>
+; CHECK-NEXT:    [[TMP1:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> [[AB_BOOL]], <vscale x 16 x i8> [[CD_BOOL]])
+; CHECK-NEXT:    [[ABCD_CMP:%.*]] = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpne.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> zeroinitializer, <vscale x 16 x i8> [[TMP1]])
+; CHECK-NEXT:    [[ABCD_BOOL:%.*]] = zext <vscale x 16 x i1> [[ABCD_CMP]] to <vscale x 16 x i8>
+; CHECK-NEXT:    call void (...) @llvm.fake.use(<vscale x 16 x i8> [[TMP1]])
+; CHECK-NEXT:    ret <vscale x 16 x i8> [[ABCD_BOOL]]
+;
+  %ab = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> %a, <vscale x 16 x i8> %b)
+  %ab.cmp = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpne.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> zeroinitializer, <vscale x 16 x i8> %ab)
+  %ab.bool = zext <vscale x 16 x i1> %ab.cmp to <vscale x 16 x i8>
+  %cd = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> %c, <vscale x 16 x i8> %d)
+  %cd.cmp = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpne.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> zeroinitializer, <vscale x 16 x i8> %cd)
+  %cd.bool = zext <vscale x 16 x i1> %cd.cmp to <vscale x 16 x i8>
+  %abcd = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> %ab.bool, <vscale x 16 x i8> %cd.bool)
+  %abcd.cmp = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpne.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> zeroinitializer, <vscale x 16 x i8> %abcd)
+  %abcd.bool = zext <vscale x 16 x i1> %abcd.cmp to <vscale x 16 x i8>
+  call void (...) @llvm.fake.use(<vscale x 16 x i8> %abcd)
+  ret <vscale x 16 x i8> %abcd.bool
+}
+
+define <vscale x 16 x i8> @logical_bool_tree_nonzero_outer_cmp_i8(<vscale x 16 x i8> %a, <vscale x 16 x i8> %b, <vscale x 16 x i8> %c, <vscale x 16 x i8> %d, <vscale x 16 x i8> %mask) #0 {
+; CHECK-LABEL: define <vscale x 16 x i8> @logical_bool_tree_nonzero_outer_cmp_i8(
+; CHECK-SAME: <vscale x 16 x i8> [[A:%.*]], <vscale x 16 x i8> [[B:%.*]], <vscale x 16 x i8> [[C:%.*]], <vscale x 16 x i8> [[D:%.*]], <vscale x 16 x i8> [[MASK:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[AB:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> [[A]], <vscale x 16 x i8> [[B]])
+; CHECK-NEXT:    [[AB_CMP:%.*]] = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpne.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> zeroinitializer, <vscale x 16 x i8> [[AB]])
+; CHECK-NEXT:    [[AB_BOOL:%.*]] = zext <vscale x 16 x i1> [[AB_CMP]] to <vscale x 16 x i8>
+; CHECK-NEXT:    [[CD:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> [[C]], <vscale x 16 x i8> [[D]])
+; CHECK-NEXT:    [[CD_CMP:%.*]] = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpne.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> zeroinitializer, <vscale x 16 x i8> [[CD]])
+; CHECK-NEXT:    [[CD_BOOL:%.*]] = zext <vscale x 16 x i1> [[CD_CMP]] to <vscale x 16 x i8>
+; CHECK-NEXT:    [[ABCD:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> [[AB_BOOL]], <vscale x 16 x i8> [[CD_BOOL]])
+; CHECK-NEXT:    [[ABCD_CMP:%.*]] = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpne.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> [[MASK]], <vscale x 16 x i8> [[ABCD]])
+; CHECK-NEXT:    [[ABCD_BOOL:%.*]] = zext <vscale x 16 x i1> [[ABCD_CMP]] to <vscale x 16 x i8>
+; CHECK-NEXT:    ret <vscale x 16 x i8> [[ABCD_BOOL]]
+;
+  %ab = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> %a, <vscale x 16 x i8> %b)
+  %ab.cmp = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpne.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> zeroinitializer, <vscale x 16 x i8> %ab)
+  %ab.bool = zext <vscale x 16 x i1> %ab.cmp to <vscale x 16 x i8>
+  %cd = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> %c, <vscale x 16 x i8> %d)
+  %cd.cmp = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpne.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> zeroinitializer, <vscale x 16 x i8> %cd)
+  %cd.bool = zext <vscale x 16 x i1> %cd.cmp to <vscale x 16 x i8>
+  %abcd = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> %ab.bool, <vscale x 16 x i8> %cd.bool)
+  %abcd.cmp = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpne.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> %mask, <vscale x 16 x i8> %abcd)
+  %abcd.bool = zext <vscale x 16 x i1> %abcd.cmp to <vscale x 16 x i8>
+  ret <vscale x 16 x i8> %abcd.bool
+}
+
+define <vscale x 16 x i8> @logical_bool_tree_inactive_predicate_i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a, <vscale x 16 x i8> %b, <vscale x 16 x i8> %c, <vscale x 16 x i8> %d) #0 {
+; CHECK-LABEL: define <vscale x 16 x i8> @logical_bool_tree_inactive_predicate_i8(
+; CHECK-SAME: <vscale x 16 x i1> [[PG:%.*]], <vscale x 16 x i8> [[A:%.*]], <vscale x 16 x i8> [[B:%.*]], <vscale x 16 x i8> [[C:%.*]], <vscale x 16 x i8> [[D:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[AB:%.*]] = 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> [[B]])
+; CHECK-NEXT:    [[AB_CMP:%.*]] = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpne.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> zeroinitializer, <vscale x 16 x i8> [[AB]])
+; CHECK-NEXT:    [[AB_BOOL:%.*]] = zext <vscale x 16 x i1> [[AB_CMP]] to <vscale x 16 x i8>
+; CHECK-NEXT:    [[CD:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[C]], <vscale x 16 x i8> [[D]])
+; CHECK-NEXT:    [[CD_CMP:%.*]] = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpne.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> zeroinitializer, <vscale x 16 x i8> [[CD]])
+; CHECK-NEXT:    [[CD_BOOL:%.*]] = zext <vscale x 16 x i1> [[CD_CMP]] to <vscale x 16 x i8>
+; CHECK-NEXT:    [[ABCD:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[AB_BOOL]], <vscale x 16 x i8> [[CD_BOOL]])
+; CHECK-NEXT:    [[ABCD_CMP:%.*]] = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpne.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> zeroinitializer, <vscale x 16 x i8> [[ABCD]])
+; CHECK-NEXT:    [[ABCD_BOOL:%.*]] = zext <vscale x 16 x i1> [[ABCD_CMP]] to <vscale x 16 x i8>
+; CHECK-NEXT:    ret <vscale x 16 x i8> [[ABCD_BOOL]]
+;
+  %ab = 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> %b)
+  %ab.cmp = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpne.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> zeroinitializer, <vscale x 16 x i8> %ab)
+  %ab.bool = zext <vscale x 16 x i1> %ab.cmp to <vscale x 16 x i8>
+  %cd = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %c, <vscale x 16 x i8> %d)
+  %cd.cmp = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpne.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> zeroinitializer, <vscale x 16 x i8> %cd)
+  %cd.bool = zext <vscale x 16 x i1> %cd.cmp to <vscale x 16 x i8>
+  %abcd = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %ab.bool, <vscale x 16 x i8> %cd.bool)
+  %abcd.cmp = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpne.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> zeroinitializer, <vscale x 16 x i8> %abcd)
+  %abcd.bool = zext <vscale x 16 x i1> %abcd.cmp to <vscale x 16 x i8>
+  ret <vscale x 16 x i8> %abcd.bool
+}
+
+define <vscale x 16 x i16> @logical_bool_tree_wide_final_zext_i8(<vscale x 16 x i8> %a, <vscale x 16 x i8> %b, <vscale x 16 x i8> %c, <vscale x 16 x i8> %d) #0 {
+; CHECK-LABEL: define <vscale x 16 x i16> @logical_bool_tree_wide_final_zext_i8(
+; CHECK-SAME: <vscale x 16 x i8> [[A:%.*]], <vscale x 16 x i8> [[B:%.*]], <vscale x 16 x i8> [[C:%.*]], <vscale x 16 x i8> [[D:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[AB:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> [[A]], <vscale x 16 x i8> [[B]])
+; CHECK-NEXT:    [[AB_CMP:%.*]] = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpne.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> zeroinitializer, <vscale x 16 x i8> [[AB]])
+; CHECK-NEXT:    [[AB_BOOL:%.*]] = zext <vscale x 16 x i1> [[AB_CMP]] to <vscale x 16 x i8>
+; CHECK-NEXT:    [[CD:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> [[C]], <vscale x 16 x i8> [[D]])
+; CHECK-NEXT:    [[CD_CMP:%.*]] = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpne.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> zeroinitializer, <vscale x 16 x i8> [[CD]])
+; CHECK-NEXT:    [[CD_BOOL:%.*]] = zext <vscale x 16 x i1> [[CD_CMP]] to <vscale x 16 x i8>
+; CHECK-NEXT:    [[ABCD:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> [[AB_BOOL]], <vscale x 16 x i8> [[CD_BOOL]])
+; CHECK-NEXT:    [[ABCD_CMP:%.*]] = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpne.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> zeroinitializer, <vscale x 16 x i8> [[ABCD]])
+; CHECK-NEXT:    [[ABCD_BOOL:%.*]] = zext <vscale x 16 x i1> [[ABCD_CMP]] to <vscale x 16 x i16>
+; CHECK-NEXT:    ret <vscale x 16 x i16> [[ABCD_BOOL]]
+;
+  %ab = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> %a, <vscale x 16 x i8> %b)
+  %ab.cmp = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpne.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> zeroinitializer, <vscale x 16 x i8> %ab)
+  %ab.bool = zext <vscale x 16 x i1> %ab.cmp to <vscale x 16 x i8>
+  %cd = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> %c, <vscale x 16 x i8> %d)
+  %cd.cmp = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpne.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> zeroinitializer, <vscale x 16 x i8> %cd)
+  %cd.bool = zext <vscale x 16 x i1> %cd.cmp to <vscale x 16 x i8>
+  %abcd = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> %ab.bool, <vscale x 16 x i8> %cd.bool)
+  %abcd.cmp = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpne.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> zeroinitializer, <vscale x 16 x i8> %abcd)
+  %abcd.bool = zext <vscale x 16 x i1> %abcd.cmp to <vscale x 16 x i16>
+  ret <vscale x 16 x i16> %abcd.bool
+}
+
+define <vscale x 16 x i16> @logical_bool_tree_wide_inner_zext_i8(<vscale x 16 x i8> %a, <vscale x 16 x i8> %b, <vscale x 16 x i8> %c, <vscale x 16 x i8> %d) #0 {
+; CHECK-LABEL: define <vscale x 16 x i16> @logical_bool_tree_wide_inner_zext_i8(
+; CHECK-SAME: <vscale x 16 x i8> [[A:%.*]], <vscale x 16 x i8> [[B:%.*]], <vscale x 16 x i8> [[C:%.*]], <vscale x 16 x i8> [[D:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[AB:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> [[A]], <vscale x 16 x i8> [[B]])
+; CHECK-NEXT:    [[AB_CMP:%.*]] = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpne.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> zeroinitializer, <vscale x 16 x i8> [[AB]])
+; CHECK-NEXT:    [[AB_BOOL:%.*]] = zext <vscale x 16 x i1> [[AB_CMP]] to <vscale x 16 x i16>
+; CHECK-NEXT:    [[CD:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> [[C]], <vscale x 16 x i8> [[D]])
+; CHECK-NEXT:    [[CD_CMP:%.*]] = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpne.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> zeroinitializer, <vscale x 16 x i8> [[CD]])
+; CHECK-NEXT:    [[CD_BOOL:%.*]] = zext <vscale x 16 x i1> [[CD_CMP]] to <vscale x 16 x i16>
+; CHECK-NEXT:    [[ABCD:%.*]] = call <vscale x 16 x i16> @llvm.aarch64.sve.umin.u.nxv16i16(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i16> [[AB_BOOL]], <vscale x 16 x i16> [[CD_BOOL]])
+; CHECK-NEXT:    [[ABCD_CMP:%.*]] = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpne.nxv16i16(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i16> zeroinitializer, <vscale x 16 x i16> [[ABCD]])
+; CHECK-NEXT:    [[ABCD_BOOL:%.*]] = zext <vscale x 16 x i1> [[ABCD_CMP]] to <vscale x 16 x i16>
+; CHECK-NEXT:    ret <vscale x 16 x i16> [[ABCD_BOOL]]
+;
+  %ab = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> %a, <vscale x 16 x i8> %b)
+  %ab.cmp = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpne.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x...
[truncated]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend:AArch64 llvm:instcombine Covers the InstCombine, InstSimplify and AggressiveInstCombine passes llvm:transforms

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant