[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