[llvm] [AArch64][SVE] Optimize logical ops with convert.to.svbool (PR #160408)

Vladimir Miloserdov via llvm-commits llvm-commits at lists.llvm.org
Sat Aug 15 12:38:11 PDT 2026


https://github.com/miloserdow updated https://github.com/llvm/llvm-project/pull/160408

>From 3b65edb96ecad24d6d0f5d44fefa651aac066993 Mon Sep 17 00:00:00 2001
From: Vladimir Miloserdov <milosvova at gmail.com>
Date: Tue, 23 Sep 2025 23:07:05 +0100
Subject: [PATCH] [AArch64][SVE] Optimize logical ops with convert.to.svbool

When both operands of a logical operation (and/or/xor) are convert.to.svbool
from the same narrower type, unwrap to that type, simplify using simplifyBinOp,
and rewrap the result. This eliminates redundant instructions in cases like:
 svand_z(svptrue_b8(), svpnext_b16(prev, pg), svptrue_b16());

Fixes #160279.
---
 .../AArch64/AArch64TargetTransformInfo.cpp    |  28 ++
 .../sve-intrinsic-and-or-with-all-true.ll     | 279 ++++++++++++++++++
 2 files changed, 307 insertions(+)
 create mode 100644 llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-and-or-with-all-true.ll

diff --git a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
index 2e28901cc5127..3a17f82cf745f 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
@@ -2014,6 +2014,34 @@ simplifySVEIntrinsicBinOp(InstCombiner &IC, IntrinsicInst &II,
   else
     SimpleII = simplifyBinOp(Opc, Op1, Op2, DL);
 
+  // If both operands are convert.to.svbool from the same narrower predicate
+  // type, try to simplify the operation at that narrower type. This is valid
+  // because the conversions zero the lanes not represented by the narrower
+  // type, so those lanes of the result are zero either way.
+  Value *NarrowOp1, *NarrowOp2;
+  if (!SimpleII &&
+      match(Op1, m_Intrinsic<Intrinsic::aarch64_sve_convert_to_svbool>(
+                     m_Value(NarrowOp1))) &&
+      match(Op2, m_Intrinsic<Intrinsic::aarch64_sve_convert_to_svbool>(
+                     m_Value(NarrowOp2))) &&
+      NarrowOp1->getType() == NarrowOp2->getType() &&
+      NarrowOp1->getType()->isScalableTy() &&
+      NarrowOp1->getType()->isIntOrIntVectorTy(1)) {
+    Value *SimpleNarrow = simplifyBinOp(Opc, NarrowOp1, NarrowOp2, DL);
+    if (SimpleNarrow && !isa<UndefValue>(SimpleNarrow)) {
+      if (match(SimpleNarrow, m_ZeroInt()))
+        SimpleII = Constant::getNullValue(II.getType());
+      else if (SimpleNarrow == NarrowOp1)
+        SimpleII = Op1;
+      else if (SimpleNarrow == NarrowOp2)
+        SimpleII = Op2;
+      else
+        SimpleII = IC.Builder.CreateIntrinsic(
+            Intrinsic::aarch64_sve_convert_to_svbool, {SimpleNarrow->getType()},
+            {SimpleNarrow});
+    }
+  }
+
   // An SVE intrinsic's result is always defined. However, this is not the case
   // for its equivalent IR instruction (e.g. when shifting by an amount more
   // than the data's bitwidth). Simplifications to an undefined result must be
diff --git a/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-and-or-with-all-true.ll b/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-and-or-with-all-true.ll
new file mode 100644
index 0000000000000..910a77c720cdc
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-and-or-with-all-true.ll
@@ -0,0 +1,279 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -S -passes=instcombine < %s | FileCheck %s
+
+target triple = "aarch64-unknown-linux-gnu"
+
+; Test AArch64-specific InstCombine optimizations for SVE logical operations
+; whose operands are convert.to.svbool from a narrower predicate type.
+; - a AND true = a
+; - a OR true = true
+
+define <vscale x 16 x i1> @test_and_convert_all_true_right_b16(<vscale x 8 x i1> %x) #0 {
+; CHECK-LABEL: define <vscale x 16 x i1> @test_and_convert_all_true_right_b16(
+; CHECK-SAME: <vscale x 8 x i1> [[X:%.*]]) #[[ATTR0:[0-9]+]] {
+; CHECK-NEXT:    [[CONV_X:%.*]] = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> [[X]])
+; CHECK-NEXT:    ret <vscale x 16 x i1> [[CONV_X]]
+;
+  %conv_x = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> %x)
+  %conv_true = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> splat (i1 true))
+  %result = tail call <vscale x 16 x i1> @llvm.aarch64.sve.and.z.nxv16i1(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i1> %conv_x, <vscale x 16 x i1> %conv_true)
+  ret <vscale x 16 x i1> %result
+}
+
+define <vscale x 16 x i1> @test_and_convert_all_true_left_b16(<vscale x 8 x i1> %x) #0 {
+; CHECK-LABEL: define <vscale x 16 x i1> @test_and_convert_all_true_left_b16(
+; CHECK-SAME: <vscale x 8 x i1> [[X:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[CONV_X:%.*]] = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> [[X]])
+; CHECK-NEXT:    ret <vscale x 16 x i1> [[CONV_X]]
+;
+  %conv_x = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> %x)
+  %conv_true = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> splat (i1 true))
+  %result = tail call <vscale x 16 x i1> @llvm.aarch64.sve.and.z.nxv16i1(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i1> %conv_true, <vscale x 16 x i1> %conv_x)
+  ret <vscale x 16 x i1> %result
+}
+
+define <vscale x 16 x i1> @test_orr_convert_all_true_right_b16(<vscale x 8 x i1> %x) #0 {
+; CHECK-LABEL: define <vscale x 16 x i1> @test_orr_convert_all_true_right_b16(
+; CHECK-SAME: <vscale x 8 x i1> [[X:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[CONV_TRUE:%.*]] = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> splat (i1 true))
+; CHECK-NEXT:    ret <vscale x 16 x i1> [[CONV_TRUE]]
+;
+  %conv_x = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> %x)
+  %conv_true = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> splat (i1 true))
+  %result = tail call <vscale x 16 x i1> @llvm.aarch64.sve.orr.z.nxv16i1(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i1> %conv_x, <vscale x 16 x i1> %conv_true)
+  ret <vscale x 16 x i1> %result
+}
+
+define <vscale x 16 x i1> @test_orr_convert_all_true_left_b16(<vscale x 8 x i1> %x) #0 {
+; CHECK-LABEL: define <vscale x 16 x i1> @test_orr_convert_all_true_left_b16(
+; CHECK-SAME: <vscale x 8 x i1> [[X:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[CONV_TRUE:%.*]] = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> splat (i1 true))
+; CHECK-NEXT:    ret <vscale x 16 x i1> [[CONV_TRUE]]
+;
+  %conv_x = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> %x)
+  %conv_true = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> splat (i1 true))
+  %result = tail call <vscale x 16 x i1> @llvm.aarch64.sve.orr.z.nxv16i1(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i1> %conv_true, <vscale x 16 x i1> %conv_x)
+  ret <vscale x 16 x i1> %result
+}
+
+define <vscale x 16 x i1> @test_and_convert_all_true_b32(<vscale x 4 x i1> %x) #0 {
+; CHECK-LABEL: define <vscale x 16 x i1> @test_and_convert_all_true_b32(
+; CHECK-SAME: <vscale x 4 x i1> [[X:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[CONV_X:%.*]] = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv4i1(<vscale x 4 x i1> [[X]])
+; CHECK-NEXT:    ret <vscale x 16 x i1> [[CONV_X]]
+;
+  %conv_x = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv4i1(<vscale x 4 x i1> %x)
+  %conv_true = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv4i1(<vscale x 4 x i1> splat (i1 true))
+  %result = tail call <vscale x 16 x i1> @llvm.aarch64.sve.and.z.nxv16i1(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i1> %conv_x, <vscale x 16 x i1> %conv_true)
+  ret <vscale x 16 x i1> %result
+}
+
+define <vscale x 16 x i1> @test_and_convert_all_true_b64(<vscale x 2 x i1> %x) #0 {
+; CHECK-LABEL: define <vscale x 16 x i1> @test_and_convert_all_true_b64(
+; CHECK-SAME: <vscale x 2 x i1> [[X:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[CONV_X:%.*]] = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv2i1(<vscale x 2 x i1> [[X]])
+; CHECK-NEXT:    ret <vscale x 16 x i1> [[CONV_X]]
+;
+  %conv_x = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv2i1(<vscale x 2 x i1> %x)
+  %conv_true = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv2i1(<vscale x 2 x i1> splat (i1 true))
+  %result = tail call <vscale x 16 x i1> @llvm.aarch64.sve.and.z.nxv16i1(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i1> %conv_x, <vscale x 16 x i1> %conv_true)
+  ret <vscale x 16 x i1> %result
+}
+
+; Reproducer from https://github.com/llvm/llvm-project/issues/160279.
+define <vscale x 16 x i1> @test_and_pnext_ptrue_b16(<vscale x 16 x i1> %pg, <vscale x 16 x i1> %prev) #0 {
+; CHECK-LABEL: define <vscale x 16 x i1> @test_and_pnext_ptrue_b16(
+; CHECK-SAME: <vscale x 16 x i1> [[PG:%.*]], <vscale x 16 x i1> [[PREV:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[TMP1:%.*]] = tail call <vscale x 8 x i1> @llvm.aarch64.sve.convert.from.svbool.nxv8i1(<vscale x 16 x i1> [[PREV]])
+; CHECK-NEXT:    [[TMP2:%.*]] = tail call <vscale x 8 x i1> @llvm.aarch64.sve.convert.from.svbool.nxv8i1(<vscale x 16 x i1> [[PG]])
+; CHECK-NEXT:    [[TMP3:%.*]] = tail call <vscale x 8 x i1> @llvm.aarch64.sve.pnext.nxv8i1(<vscale x 8 x i1> [[TMP1]], <vscale x 8 x i1> [[TMP2]])
+; CHECK-NEXT:    [[TMP4:%.*]] = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> [[TMP3]])
+; CHECK-NEXT:    ret <vscale x 16 x i1> [[TMP4]]
+;
+  %1 = tail call <vscale x 8 x i1> @llvm.aarch64.sve.convert.from.svbool.nxv8i1(<vscale x 16 x i1> %prev)
+  %2 = tail call <vscale x 8 x i1> @llvm.aarch64.sve.convert.from.svbool.nxv8i1(<vscale x 16 x i1> %pg)
+  %3 = tail call <vscale x 8 x i1> @llvm.aarch64.sve.pnext.nxv8i1(<vscale x 8 x i1> %1, <vscale x 8 x i1> %2)
+  %4 = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> %3)
+  %5 = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> splat (i1 true))
+  %6 = tail call <vscale x 16 x i1> @llvm.aarch64.sve.and.z.nxv16i1(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i1> %4, <vscale x 16 x i1> %5)
+  ret <vscale x 16 x i1> %6
+}
+
+define <vscale x 16 x i1> @test_eor_convert_same(<vscale x 8 x i1> %x) #0 {
+; CHECK-LABEL: define <vscale x 16 x i1> @test_eor_convert_same(
+; CHECK-SAME: <vscale x 8 x i1> [[X:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    ret <vscale x 16 x i1> zeroinitializer
+;
+  %conv_x = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> %x)
+  %result = tail call <vscale x 16 x i1> @llvm.aarch64.sve.eor.z.nxv16i1(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i1> %conv_x, <vscale x 16 x i1> %conv_x)
+  ret <vscale x 16 x i1> %result
+}
+
+define <vscale x 16 x i1> @test_eor_convert_zero(<vscale x 8 x i1> %x) #0 {
+; CHECK-LABEL: define <vscale x 16 x i1> @test_eor_convert_zero(
+; CHECK-SAME: <vscale x 8 x i1> [[X:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[CONV_X:%.*]] = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> [[X]])
+; CHECK-NEXT:    ret <vscale x 16 x i1> [[CONV_X]]
+;
+  %conv_x = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> %x)
+  %conv_zero = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> zeroinitializer)
+  %result = tail call <vscale x 16 x i1> @llvm.aarch64.sve.eor.z.nxv16i1(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i1> %conv_x, <vscale x 16 x i1> %conv_zero)
+  ret <vscale x 16 x i1> %result
+}
+
+define <vscale x 16 x i1> @test_and_convert_zero(<vscale x 8 x i1> %x) #0 {
+; CHECK-LABEL: define <vscale x 16 x i1> @test_and_convert_zero(
+; CHECK-SAME: <vscale x 8 x i1> [[X:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    ret <vscale x 16 x i1> zeroinitializer
+;
+  %conv_x = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> %x)
+  %conv_zero = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> zeroinitializer)
+  %result = tail call <vscale x 16 x i1> @llvm.aarch64.sve.and.z.nxv16i1(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i1> %conv_x, <vscale x 16 x i1> %conv_zero)
+  ret <vscale x 16 x i1> %result
+}
+
+define <vscale x 16 x i1> @test_orr_convert_zero(<vscale x 8 x i1> %x) #0 {
+; CHECK-LABEL: define <vscale x 16 x i1> @test_orr_convert_zero(
+; CHECK-SAME: <vscale x 8 x i1> [[X:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[CONV_X:%.*]] = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> [[X]])
+; CHECK-NEXT:    ret <vscale x 16 x i1> [[CONV_X]]
+;
+  %conv_x = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> %x)
+  %conv_zero = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> zeroinitializer)
+  %result = tail call <vscale x 16 x i1> @llvm.aarch64.sve.orr.z.nxv16i1(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i1> %conv_x, <vscale x 16 x i1> %conv_zero)
+  ret <vscale x 16 x i1> %result
+}
+
+define <vscale x 16 x i1> @test_orr_convert_complement(<vscale x 8 x i1> %x) #0 {
+; CHECK-LABEL: define <vscale x 16 x i1> @test_orr_convert_complement(
+; CHECK-SAME: <vscale x 8 x i1> [[X:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[TMP1:%.*]] = call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> splat (i1 true))
+; CHECK-NEXT:    ret <vscale x 16 x i1> [[TMP1]]
+;
+  %not_x = xor <vscale x 8 x i1> %x, splat (i1 true)
+  %conv_x = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> %x)
+  %conv_not_x = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> %not_x)
+  %result = tail call <vscale x 16 x i1> @llvm.aarch64.sve.orr.z.nxv16i1(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i1> %conv_x, <vscale x 16 x i1> %conv_not_x)
+  ret <vscale x 16 x i1> %result
+}
+
+define { <vscale x 16 x i1>, <vscale x 16 x i1> } @test_and_convert_multiuse(<vscale x 8 x i1> %x) #0 {
+; CHECK-LABEL: define { <vscale x 16 x i1>, <vscale x 16 x i1> } @test_and_convert_multiuse(
+; CHECK-SAME: <vscale x 8 x i1> [[X:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[CONV_X:%.*]] = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> [[X]])
+; CHECK-NEXT:    [[RET0:%.*]] = insertvalue { <vscale x 16 x i1>, <vscale x 16 x i1> } poison, <vscale x 16 x i1> [[CONV_X]], 0
+; CHECK-NEXT:    [[RET1:%.*]] = insertvalue { <vscale x 16 x i1>, <vscale x 16 x i1> } [[RET0]], <vscale x 16 x i1> [[CONV_X]], 1
+; CHECK-NEXT:    ret { <vscale x 16 x i1>, <vscale x 16 x i1> } [[RET1]]
+;
+  %conv_x = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> %x)
+  %conv_true = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> splat (i1 true))
+  %result = tail call <vscale x 16 x i1> @llvm.aarch64.sve.and.z.nxv16i1(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i1> %conv_x, <vscale x 16 x i1> %conv_true)
+  %ret0 = insertvalue { <vscale x 16 x i1>, <vscale x 16 x i1> } poison, <vscale x 16 x i1> %result, 0
+  %ret1 = insertvalue { <vscale x 16 x i1>, <vscale x 16 x i1> } %ret0, <vscale x 16 x i1> %conv_x, 1
+  ret { <vscale x 16 x i1>, <vscale x 16 x i1> } %ret1
+}
+
+define <vscale x 16 x i1> @test_and_convert_any_predicate(<vscale x 16 x i1> %pred, <vscale x 8 x i1> %x) #0 {
+; CHECK-LABEL: define <vscale x 16 x i1> @test_and_convert_any_predicate(
+; CHECK-SAME: <vscale x 16 x i1> [[PRED:%.*]], <vscale x 8 x i1> [[X:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[CONV_X:%.*]] = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> [[X]])
+; CHECK-NEXT:    [[RESULT:%.*]] = select <vscale x 16 x i1> [[PRED]], <vscale x 16 x i1> [[CONV_X]], <vscale x 16 x i1> zeroinitializer
+; CHECK-NEXT:    ret <vscale x 16 x i1> [[RESULT]]
+;
+  %conv_x = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> %x)
+  %conv_true = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> splat (i1 true))
+  %result = tail call <vscale x 16 x i1> @llvm.aarch64.sve.and.z.nxv16i1(<vscale x 16 x i1> %pred, <vscale x 16 x i1> %conv_x, <vscale x 16 x i1> %conv_true)
+  ret <vscale x 16 x i1> %result
+}
+
+define <vscale x 16 x i1> @test_and_pg_widened_true(<vscale x 8 x i1> %x) #0 {
+; CHECK-LABEL: define <vscale x 16 x i1> @test_and_pg_widened_true(
+; CHECK-SAME: <vscale x 8 x i1> [[X:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[PG:%.*]] = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> splat (i1 true))
+; CHECK-NEXT:    [[CONV_X:%.*]] = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> [[X]])
+; CHECK-NEXT:    [[RESULT:%.*]] = select <vscale x 16 x i1> [[PG]], <vscale x 16 x i1> [[CONV_X]], <vscale x 16 x i1> zeroinitializer
+; CHECK-NEXT:    ret <vscale x 16 x i1> [[RESULT]]
+;
+  %pg = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> splat (i1 true))
+  %conv_x = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> %x)
+  %conv_true = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> splat (i1 true))
+  %result = tail call <vscale x 16 x i1> @llvm.aarch64.sve.and.z.nxv16i1(<vscale x 16 x i1> %pg, <vscale x 16 x i1> %conv_x, <vscale x 16 x i1> %conv_true)
+  ret <vscale x 16 x i1> %result
+}
+
+; Negative test
+define <vscale x 16 x i1> @test_eor_convert_all_true(<vscale x 8 x i1> %x) #0 {
+; CHECK-LABEL: define <vscale x 16 x i1> @test_eor_convert_all_true(
+; CHECK-SAME: <vscale x 8 x i1> [[X:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[CONV_X:%.*]] = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> [[X]])
+; CHECK-NEXT:    [[CONV_TRUE:%.*]] = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> splat (i1 true))
+; CHECK-NEXT:    [[RESULT:%.*]] = tail call <vscale x 16 x i1> @llvm.aarch64.sve.eor.z.nxv16i1(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i1> [[CONV_X]], <vscale x 16 x i1> [[CONV_TRUE]])
+; CHECK-NEXT:    ret <vscale x 16 x i1> [[RESULT]]
+;
+  %conv_x = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> %x)
+  %conv_true = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> splat (i1 true))
+  %result = tail call <vscale x 16 x i1> @llvm.aarch64.sve.eor.z.nxv16i1(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i1> %conv_x, <vscale x 16 x i1> %conv_true)
+  ret <vscale x 16 x i1> %result
+}
+
+; Negative test
+define <vscale x 16 x i1> @test_and_convert_poison(<vscale x 8 x i1> %x) #0 {
+; CHECK-LABEL: define <vscale x 16 x i1> @test_and_convert_poison(
+; CHECK-SAME: <vscale x 8 x i1> [[X:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[CONV_X:%.*]] = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> [[X]])
+; CHECK-NEXT:    [[CONV_POISON:%.*]] = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> poison)
+; CHECK-NEXT:    [[RESULT:%.*]] = tail call <vscale x 16 x i1> @llvm.aarch64.sve.and.z.nxv16i1(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i1> [[CONV_X]], <vscale x 16 x i1> [[CONV_POISON]])
+; CHECK-NEXT:    ret <vscale x 16 x i1> [[RESULT]]
+;
+  %conv_x = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> %x)
+  %conv_poison = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> poison)
+  %result = tail call <vscale x 16 x i1> @llvm.aarch64.sve.and.z.nxv16i1(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i1> %conv_x, <vscale x 16 x i1> %conv_poison)
+  ret <vscale x 16 x i1> %result
+}
+
+; Negative test
+define <vscale x 16 x i1> @test_and_convert_different_granularities(<vscale x 8 x i1> %x, <vscale x 4 x i1> %y) #0 {
+; CHECK-LABEL: define <vscale x 16 x i1> @test_and_convert_different_granularities(
+; CHECK-SAME: <vscale x 8 x i1> [[X:%.*]], <vscale x 4 x i1> [[Y:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[CONV_X:%.*]] = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> [[X]])
+; CHECK-NEXT:    [[CONV_Y:%.*]] = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv4i1(<vscale x 4 x i1> [[Y]])
+; CHECK-NEXT:    [[RESULT:%.*]] = tail call <vscale x 16 x i1> @llvm.aarch64.sve.and.z.nxv16i1(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i1> [[CONV_X]], <vscale x 16 x i1> [[CONV_Y]])
+; CHECK-NEXT:    ret <vscale x 16 x i1> [[RESULT]]
+;
+  %conv_x = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> %x)
+  %conv_y = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv4i1(<vscale x 4 x i1> %y)
+  %result = tail call <vscale x 16 x i1> @llvm.aarch64.sve.and.z.nxv16i1(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i1> %conv_x, <vscale x 16 x i1> %conv_y)
+  ret <vscale x 16 x i1> %result
+}
+
+; Negative test
+define <vscale x 16 x i1> @test_and_convert_no_all_true(<vscale x 8 x i1> %x, <vscale x 8 x i1> %y) #0 {
+; CHECK-LABEL: define <vscale x 16 x i1> @test_and_convert_no_all_true(
+; CHECK-SAME: <vscale x 8 x i1> [[X:%.*]], <vscale x 8 x i1> [[Y:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[CONV_X:%.*]] = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> [[X]])
+; CHECK-NEXT:    [[CONV_Y:%.*]] = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> [[Y]])
+; CHECK-NEXT:    [[RESULT:%.*]] = tail call <vscale x 16 x i1> @llvm.aarch64.sve.and.z.nxv16i1(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i1> [[CONV_X]], <vscale x 16 x i1> [[CONV_Y]])
+; CHECK-NEXT:    ret <vscale x 16 x i1> [[RESULT]]
+;
+  %conv_x = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> %x)
+  %conv_y = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> %y)
+  %result = tail call <vscale x 16 x i1> @llvm.aarch64.sve.and.z.nxv16i1(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i1> %conv_x, <vscale x 16 x i1> %conv_y)
+  ret <vscale x 16 x i1> %result
+}
+
+; Negative test
+define <vscale x 16 x i1> @test_orr_convert_svcount(target("aarch64.svcount") %a) #0 {
+; CHECK-LABEL: define <vscale x 16 x i1> @test_orr_convert_svcount(
+; CHECK-SAME: target("aarch64.svcount") [[A:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[CONV_A1:%.*]] = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.taarch64.svcountt(target("aarch64.svcount") [[A]])
+; CHECK-NEXT:    [[CONV_A2:%.*]] = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.taarch64.svcountt(target("aarch64.svcount") [[A]])
+; CHECK-NEXT:    [[RESULT:%.*]] = tail call <vscale x 16 x i1> @llvm.aarch64.sve.orr.z.nxv16i1(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i1> [[CONV_A1]], <vscale x 16 x i1> [[CONV_A2]])
+; CHECK-NEXT:    ret <vscale x 16 x i1> [[RESULT]]
+;
+  %conv_a1 = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.taarch64.svcountt(target("aarch64.svcount") %a)
+  %conv_a2 = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.taarch64.svcountt(target("aarch64.svcount") %a)
+  %result = tail call <vscale x 16 x i1> @llvm.aarch64.sve.orr.z.nxv16i1(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i1> %conv_a1, <vscale x 16 x i1> %conv_a2)
+  ret <vscale x 16 x i1> %result
+}
+
+attributes #0 = { "target-features"="+sve" }



More information about the llvm-commits mailing list