[llvm] [LLVM][InstCombine][SVE] Canonicalise sve.ptrue(SV_POW2) to splat(i1 true). (PR #203556)
Paul Walker via llvm-commits
llvm-commits at lists.llvm.org
Fri Jun 12 08:08:18 PDT 2026
https://github.com/paulwalker-arm created https://github.com/llvm/llvm-project/pull/203556
SVE vectors must be a power-of-two in length, making pow2 synonymous with all.
NOTE: I wasn't sure about the intent of the tests in sve-intrinsics-ptest.ll but figured `0 (SV_POW2)` is being used as a proxy for `!= 31` and so changed it to something else that ensures the output IR matches the input. Given I had to edit the test I decided to remove the redundant function declarations.
>From f3b9af412112338835fbc8a8903b81890d44739e Mon Sep 17 00:00:00 2001
From: Paul Walker <paul.walker at arm.com>
Date: Fri, 12 Jun 2026 14:27:53 +0100
Subject: [PATCH 1/2] Add instcombine test for ptrue covering all supported
pattern values.
---
.../AArch64/sve-intrinsic-ptrue.ll | 158 ++++++++++++++++++
1 file changed, 158 insertions(+)
create mode 100644 llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-ptrue.ll
diff --git a/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-ptrue.ll b/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-ptrue.ll
new file mode 100644
index 0000000000000..05949d9abe3f4
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-ptrue.ll
@@ -0,0 +1,158 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S -passes=instcombine < %s | FileCheck %s
+
+target triple = "aarch64-unknown-linux-gnu"
+
+define <vscale x 16 x i1> @ptrue_pow2(<vscale x 16 x i1> %a) #0 {
+; CHECK-LABEL: @ptrue_pow2(
+; CHECK-NEXT: [[MASK:%.*]] = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue.nxv16i1(i32 0)
+; CHECK-NEXT: ret <vscale x 16 x i1> [[MASK]]
+;
+ %mask = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue(i32 0)
+ ret <vscale x 16 x i1> %mask
+}
+
+define <vscale x 16 x i1> @ptrue_vl1(<vscale x 16 x i1> %a) #0 {
+; CHECK-LABEL: @ptrue_vl1(
+; CHECK-NEXT: [[MASK:%.*]] = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue.nxv16i1(i32 1)
+; CHECK-NEXT: ret <vscale x 16 x i1> [[MASK]]
+;
+ %mask = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue(i32 1)
+ ret <vscale x 16 x i1> %mask
+}
+
+define <vscale x 16 x i1> @ptrue_vl2(<vscale x 16 x i1> %a) #0 {
+; CHECK-LABEL: @ptrue_vl2(
+; CHECK-NEXT: [[MASK:%.*]] = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue.nxv16i1(i32 2)
+; CHECK-NEXT: ret <vscale x 16 x i1> [[MASK]]
+;
+ %mask = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue(i32 2)
+ ret <vscale x 16 x i1> %mask
+}
+
+define <vscale x 16 x i1> @ptrue_vl3(<vscale x 16 x i1> %a) #0 {
+; CHECK-LABEL: @ptrue_vl3(
+; CHECK-NEXT: [[MASK:%.*]] = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue.nxv16i1(i32 3)
+; CHECK-NEXT: ret <vscale x 16 x i1> [[MASK]]
+;
+ %mask = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue(i32 3)
+ ret <vscale x 16 x i1> %mask
+}
+
+define <vscale x 16 x i1> @ptrue_vl4(<vscale x 16 x i1> %a) #0 {
+; CHECK-LABEL: @ptrue_vl4(
+; CHECK-NEXT: [[MASK:%.*]] = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue.nxv16i1(i32 4)
+; CHECK-NEXT: ret <vscale x 16 x i1> [[MASK]]
+;
+ %mask = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue(i32 4)
+ ret <vscale x 16 x i1> %mask
+}
+
+define <vscale x 16 x i1> @ptrue_vl5(<vscale x 16 x i1> %a) #0 {
+; CHECK-LABEL: @ptrue_vl5(
+; CHECK-NEXT: [[MASK:%.*]] = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue.nxv16i1(i32 5)
+; CHECK-NEXT: ret <vscale x 16 x i1> [[MASK]]
+;
+ %mask = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue(i32 5)
+ ret <vscale x 16 x i1> %mask
+}
+
+define <vscale x 16 x i1> @ptrue_vl6(<vscale x 16 x i1> %a) #0 {
+; CHECK-LABEL: @ptrue_vl6(
+; CHECK-NEXT: [[MASK:%.*]] = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue.nxv16i1(i32 6)
+; CHECK-NEXT: ret <vscale x 16 x i1> [[MASK]]
+;
+ %mask = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue(i32 6)
+ ret <vscale x 16 x i1> %mask
+}
+
+define <vscale x 16 x i1> @ptrue_vl7(<vscale x 16 x i1> %a) #0 {
+; CHECK-LABEL: @ptrue_vl7(
+; CHECK-NEXT: [[MASK:%.*]] = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue.nxv16i1(i32 7)
+; CHECK-NEXT: ret <vscale x 16 x i1> [[MASK]]
+;
+ %mask = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue(i32 7)
+ ret <vscale x 16 x i1> %mask
+}
+
+define <vscale x 16 x i1> @ptrue_vl8(<vscale x 16 x i1> %a) #0 {
+; CHECK-LABEL: @ptrue_vl8(
+; CHECK-NEXT: [[MASK:%.*]] = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue.nxv16i1(i32 8)
+; CHECK-NEXT: ret <vscale x 16 x i1> [[MASK]]
+;
+ %mask = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue(i32 8)
+ ret <vscale x 16 x i1> %mask
+}
+
+define <vscale x 16 x i1> @ptrue_vl16(<vscale x 16 x i1> %a) #0 {
+; CHECK-LABEL: @ptrue_vl16(
+; CHECK-NEXT: [[MASK:%.*]] = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue.nxv16i1(i32 9)
+; CHECK-NEXT: ret <vscale x 16 x i1> [[MASK]]
+;
+ %mask = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue(i32 9)
+ ret <vscale x 16 x i1> %mask
+}
+
+define <vscale x 16 x i1> @ptrue_vl32(<vscale x 16 x i1> %a) #0 {
+; CHECK-LABEL: @ptrue_vl32(
+; CHECK-NEXT: [[MASK:%.*]] = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue.nxv16i1(i32 10)
+; CHECK-NEXT: ret <vscale x 16 x i1> [[MASK]]
+;
+ %mask = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue(i32 10)
+ ret <vscale x 16 x i1> %mask
+}
+
+define <vscale x 16 x i1> @ptrue_vl64(<vscale x 16 x i1> %a) #0 {
+; CHECK-LABEL: @ptrue_vl64(
+; CHECK-NEXT: [[MASK:%.*]] = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue.nxv16i1(i32 11)
+; CHECK-NEXT: ret <vscale x 16 x i1> [[MASK]]
+;
+ %mask = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue(i32 11)
+ ret <vscale x 16 x i1> %mask
+}
+
+define <vscale x 16 x i1> @ptrue_vl128(<vscale x 16 x i1> %a) #0 {
+; CHECK-LABEL: @ptrue_vl128(
+; CHECK-NEXT: [[MASK:%.*]] = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue.nxv16i1(i32 12)
+; CHECK-NEXT: ret <vscale x 16 x i1> [[MASK]]
+;
+ %mask = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue(i32 12)
+ ret <vscale x 16 x i1> %mask
+}
+
+define <vscale x 16 x i1> @ptrue_vl256(<vscale x 16 x i1> %a) #0 {
+; CHECK-LABEL: @ptrue_vl256(
+; CHECK-NEXT: [[MASK:%.*]] = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue.nxv16i1(i32 13)
+; CHECK-NEXT: ret <vscale x 16 x i1> [[MASK]]
+;
+ %mask = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue(i32 13)
+ ret <vscale x 16 x i1> %mask
+}
+
+define <vscale x 16 x i1> @ptrue_mul4(<vscale x 16 x i1> %a) #0 {
+; CHECK-LABEL: @ptrue_mul4(
+; CHECK-NEXT: [[MASK:%.*]] = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue.nxv16i1(i32 29)
+; CHECK-NEXT: ret <vscale x 16 x i1> [[MASK]]
+;
+ %mask = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue(i32 29)
+ ret <vscale x 16 x i1> %mask
+}
+
+define <vscale x 16 x i1> @ptrue_mul3(<vscale x 16 x i1> %a) #0 {
+; CHECK-LABEL: @ptrue_mul3(
+; CHECK-NEXT: [[MASK:%.*]] = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue.nxv16i1(i32 30)
+; CHECK-NEXT: ret <vscale x 16 x i1> [[MASK]]
+;
+ %mask = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue(i32 30)
+ ret <vscale x 16 x i1> %mask
+}
+
+define <vscale x 16 x i1> @ptrue_all(<vscale x 16 x i1> %a) #0 {
+; CHECK-LABEL: @ptrue_all(
+; CHECK-NEXT: ret <vscale x 16 x i1> splat (i1 true)
+;
+ %mask = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue(i32 31)
+ ret <vscale x 16 x i1> %mask
+}
+
+attributes #0 = { "target-features"="+sve" }
>From 9a8354214e580948c96e531ce0901c16b824acf7 Mon Sep 17 00:00:00 2001
From: Paul Walker <paul.walker at arm.com>
Date: Fri, 12 Jun 2026 12:12:07 +0100
Subject: [PATCH 2/2] [LLVM][InstCombine][SVE] Canonicalise sve.ptrue(SV_POW2)
to splat(i1 true).
SVE vectors must be a power-of-two in length, making pow2 synonymous with all.
---
.../AArch64/AArch64TargetTransformInfo.cpp | 7 +++-
.../AArch64/sve-intrinsic-ptrue.ll | 3 +-
.../AArch64/sve-intrinsics-ptest.ll | 39 +++----------------
3 files changed, 12 insertions(+), 37 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
index 71077846088a2..38a76b45bdabb 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
@@ -2967,8 +2967,11 @@ static std::optional<Instruction *> instCombineWhilelo(InstCombiner &IC,
static std::optional<Instruction *> instCombinePTrue(InstCombiner &IC,
IntrinsicInst &II) {
- if (match(II.getOperand(0), m_ConstantInt<AArch64SVEPredPattern::all>()))
- return IC.replaceInstUsesWith(II, Constant::getAllOnesValue(II.getType()));
+ unsigned PredPattern = cast<ConstantInt>(II.getOperand(0))->getZExtValue();
+ // SVE vector length is a power-of-two, thus pow2 is synonymous with all.
+ if (PredPattern == AArch64SVEPredPattern::all ||
+ PredPattern == AArch64SVEPredPattern::pow2)
+ return IC.replaceInstUsesWith(II, ConstantInt::getTrue(II.getType()));
return std::nullopt;
}
diff --git a/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-ptrue.ll b/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-ptrue.ll
index 05949d9abe3f4..826d8ba3823ed 100644
--- a/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-ptrue.ll
+++ b/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-ptrue.ll
@@ -5,8 +5,7 @@ target triple = "aarch64-unknown-linux-gnu"
define <vscale x 16 x i1> @ptrue_pow2(<vscale x 16 x i1> %a) #0 {
; CHECK-LABEL: @ptrue_pow2(
-; CHECK-NEXT: [[MASK:%.*]] = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue.nxv16i1(i32 0)
-; CHECK-NEXT: ret <vscale x 16 x i1> [[MASK]]
+; CHECK-NEXT: ret <vscale x 16 x i1> splat (i1 true)
;
%mask = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue(i32 0)
ret <vscale x 16 x i1> %mask
diff --git a/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsics-ptest.ll b/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsics-ptest.ll
index e00ad68bdfacf..20dccf52ca7de 100644
--- a/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsics-ptest.ll
+++ b/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsics-ptest.ll
@@ -25,11 +25,11 @@ define i1 @ptest_last_to_any(<vscale x 16 x i1> %a) #0 {
define i1 @ptest_any1(<vscale x 2 x i1> %a) #0 {
; CHECK-LABEL: @ptest_any1(
-; CHECK-NEXT: [[MASK:%.*]] = tail call <vscale x 2 x i1> @llvm.aarch64.sve.ptrue.nxv2i1(i32 0)
+; CHECK-NEXT: [[MASK:%.*]] = tail call <vscale x 2 x i1> @llvm.aarch64.sve.ptrue.nxv2i1(i32 30)
; CHECK-NEXT: [[OUT:%.*]] = call i1 @llvm.aarch64.sve.ptest.any.nxv2i1(<vscale x 2 x i1> [[MASK]], <vscale x 2 x i1> [[A:%.*]])
; CHECK-NEXT: ret i1 [[OUT]]
;
- %mask = tail call <vscale x 2 x i1> @llvm.aarch64.sve.ptrue.nxv2i1(i32 0)
+ %mask = tail call <vscale x 2 x i1> @llvm.aarch64.sve.ptrue.nxv2i1(i32 30)
%1 = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv2i1(<vscale x 2 x i1> %mask)
%2 = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv2i1(<vscale x 2 x i1> %a)
%out = call i1 @llvm.aarch64.sve.ptest.any.nxv16i1(<vscale x 16 x i1> %1, <vscale x 16 x i1> %2)
@@ -53,11 +53,11 @@ define i1 @ptest_any2(<vscale x 4 x i1> %a) #0 {
define i1 @ptest_first(<vscale x 4 x i1> %a) #0 {
; CHECK-LABEL: @ptest_first(
-; CHECK-NEXT: [[MASK:%.*]] = tail call <vscale x 4 x i1> @llvm.aarch64.sve.ptrue.nxv4i1(i32 0)
+; CHECK-NEXT: [[MASK:%.*]] = tail call <vscale x 4 x i1> @llvm.aarch64.sve.ptrue.nxv4i1(i32 30)
; CHECK-NEXT: [[OUT:%.*]] = call i1 @llvm.aarch64.sve.ptest.first.nxv4i1(<vscale x 4 x i1> [[MASK]], <vscale x 4 x i1> [[A:%.*]])
; CHECK-NEXT: ret i1 [[OUT]]
;
- %mask = tail call <vscale x 4 x i1> @llvm.aarch64.sve.ptrue.nxv4i1(i32 0)
+ %mask = tail call <vscale x 4 x i1> @llvm.aarch64.sve.ptrue.nxv4i1(i32 30)
%1 = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv4i1(<vscale x 4 x i1> %mask)
%2 = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv4i1(<vscale x 4 x i1> %a)
%out = call i1 @llvm.aarch64.sve.ptest.first.nxv16i1(<vscale x 16 x i1> %1, <vscale x 16 x i1> %2)
@@ -76,11 +76,11 @@ define i1 @ptest_first_same_ops(<vscale x 2 x i1> %a) #0 {
define i1 @ptest_last(<vscale x 8 x i1> %a) #0 {
; CHECK-LABEL: @ptest_last(
-; CHECK-NEXT: [[MASK:%.*]] = tail call <vscale x 8 x i1> @llvm.aarch64.sve.ptrue.nxv8i1(i32 0)
+; CHECK-NEXT: [[MASK:%.*]] = tail call <vscale x 8 x i1> @llvm.aarch64.sve.ptrue.nxv8i1(i32 30)
; CHECK-NEXT: [[OUT:%.*]] = call i1 @llvm.aarch64.sve.ptest.last.nxv8i1(<vscale x 8 x i1> [[MASK]], <vscale x 8 x i1> [[A:%.*]])
; CHECK-NEXT: ret i1 [[OUT]]
;
- %mask = tail call <vscale x 8 x i1> @llvm.aarch64.sve.ptrue.nxv8i1(i32 0)
+ %mask = tail call <vscale x 8 x i1> @llvm.aarch64.sve.ptrue.nxv8i1(i32 30)
%1 = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> %mask)
%2 = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> %a)
%out = call i1 @llvm.aarch64.sve.ptest.last.nxv16i1(<vscale x 16 x i1> %1, <vscale x 16 x i1> %2)
@@ -221,31 +221,4 @@ define i1 @ptest_any_orr_z(<vscale x 16 x i1> %pg, <vscale x 16 x i1> %a, <vscal
ret i1 %2
}
-declare <vscale x 16 x i1> @llvm.aarch64.sve.ptrue.nxv16i1(i32)
-declare <vscale x 8 x i1> @llvm.aarch64.sve.ptrue.nxv8i1(i32)
-declare <vscale x 4 x i1> @llvm.aarch64.sve.ptrue.nxv4i1(i32)
-declare <vscale x 2 x i1> @llvm.aarch64.sve.ptrue.nxv2i1(i32)
-
-declare i1 @llvm.aarch64.sve.ptest.any.nxv16i1(<vscale x 16 x i1>, <vscale x 16 x i1>)
-declare i1 @llvm.aarch64.sve.ptest.first.nxv16i1(<vscale x 16 x i1>, <vscale x 16 x i1>)
-declare i1 @llvm.aarch64.sve.ptest.last.nxv16i1(<vscale x 16 x i1>, <vscale x 16 x i1>)
-
-declare <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1>)
-declare <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv4i1(<vscale x 4 x i1>)
-declare <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv2i1(<vscale x 2 x i1>)
-
-declare <vscale x 16 x i1> @llvm.aarch64.sve.brka.z.nxv16i1(<vscale x 16 x i1>, <vscale x 16 x i1>)
-declare <vscale x 16 x i1> @llvm.aarch64.sve.brkb.z.nxv16i1(<vscale x 16 x i1>, <vscale x 16 x i1>)
-declare <vscale x 16 x i1> @llvm.aarch64.sve.brkpa.z.nxv16i1(<vscale x 16 x i1>, <vscale x 16 x i1>, <vscale x 16 x i1>)
-declare <vscale x 16 x i1> @llvm.aarch64.sve.brkpb.z.nxv16i1(<vscale x 16 x i1>, <vscale x 16 x i1>, <vscale x 16 x i1>)
-declare <vscale x 16 x i1> @llvm.aarch64.sve.rdffr.z(<vscale x 16 x i1>)
-
-declare <vscale x 16 x i1> @llvm.aarch64.sve.and.z.nxv16i1(<vscale x 16 x i1>, <vscale x 16 x i1>, <vscale x 16 x i1>)
-declare <vscale x 16 x i1> @llvm.aarch64.sve.bic.z.nxv16i1(<vscale x 16 x i1>, <vscale x 16 x i1>, <vscale x 16 x i1>)
-declare <vscale x 16 x i1> @llvm.aarch64.sve.eor.z.nxv16i1(<vscale x 16 x i1>, <vscale x 16 x i1>, <vscale x 16 x i1>)
-declare <vscale x 16 x i1> @llvm.aarch64.sve.nand.z.nxv16i1(<vscale x 16 x i1>, <vscale x 16 x i1>, <vscale x 16 x i1>)
-declare <vscale x 16 x i1> @llvm.aarch64.sve.nor.z.nxv16i1(<vscale x 16 x i1>, <vscale x 16 x i1>, <vscale x 16 x i1>)
-declare <vscale x 16 x i1> @llvm.aarch64.sve.orn.z.nxv16i1(<vscale x 16 x i1>, <vscale x 16 x i1>, <vscale x 16 x i1>)
-declare <vscale x 16 x i1> @llvm.aarch64.sve.orr.z.nxv16i1(<vscale x 16 x i1>, <vscale x 16 x i1>, <vscale x 16 x i1>)
-
attributes #0 = { "target-features"="+sve" }
More information about the llvm-commits
mailing list