[llvm] [AArch64][InstCombine] Fold zext cmpne umin boolean trees (PR #209234)

Matthew Devereau via llvm-commits llvm-commits at lists.llvm.org
Tue Jul 14 03:56:04 PDT 2026


https://github.com/MDevereau updated https://github.com/llvm/llvm-project/pull/209234

>From 2723e7b1ba2ef5850f6a558aba250b93b8beebba Mon Sep 17 00:00:00 2001
From: Matt Devereau <matthew.devereau at arm.com>
Date: Wed, 8 Jul 2026 16:00:59 +0000
Subject: [PATCH] [AArch64][InstCombine] Fold zext cmpne umin boolean trees

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))))
---
 .../AArch64/AArch64TargetTransformInfo.cpp    |  66 ++++++++
 .../AArch64/sve-intrinsic-opts-cmpne.ll       | 154 ++++++++++++++++++
 2 files changed, 220 insertions(+)

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 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 i16>
+  %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 i16>
+  %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)
+  %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)
+  %abcd.bool = zext <vscale x 16 x i1> %abcd.cmp to <vscale x 16 x i16>
+  ret <vscale x 16 x i16> %abcd.bool
+}
+
 declare <vscale x 2 x i1> @llvm.aarch64.sve.ptrue.nxv2i1(i32)
 
 declare <vscale x 16 x i8> @llvm.vector.insert.nxv16i8.v16i8(<vscale x 16 x i8>, <16 x i8>, i64)



More information about the llvm-commits mailing list