[llvm] [AArch64][ISel] Prefer SVE over NEON for fixed-width bitreverse (PR #196264)
Harry Ramsey via llvm-commits
llvm-commits at lists.llvm.org
Thu May 7 02:15:04 PDT 2026
https://github.com/Harry-Ramsey created https://github.com/llvm/llvm-project/pull/196264
This commit enables SVE instructions for bitreverse where no equivalent NEON instructions exist. This commit affects the following NEON datatypes; v4i16, v8i16, v2i32, v4i32, v1i64, v2i64.
>From 64bc66c53be0dfefd08fbeca6dcf077dd513359a Mon Sep 17 00:00:00 2001
From: Harry Ramsey <harry.ramsey at arm.com>
Date: Thu, 7 May 2026 08:54:46 +0000
Subject: [PATCH 1/3] [AArch64][ISel] Prefer SVE over NEON for fixed-width
bitreverse
This commit enables SVE instructions for bitreverse where no equivalent
NEON instructions exist. This commit affects the following NEON
datatypes; v4i16, v8i16, v2i32, v4i32, v1i64, v2i64.
---
.../AArch64/sve-fixed-length-bitreverse.ll | 82 +++++++++++++++++++
1 file changed, 82 insertions(+)
create mode 100644 llvm/test/CodeGen/AArch64/sve-fixed-length-bitreverse.ll
diff --git a/llvm/test/CodeGen/AArch64/sve-fixed-length-bitreverse.ll b/llvm/test/CodeGen/AArch64/sve-fixed-length-bitreverse.ll
new file mode 100644
index 0000000000000..b59ed2ff0c77a
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/sve-fixed-length-bitreverse.ll
@@ -0,0 +1,82 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -mtriple=aarch64-linux-gnu -mattr=+sve < %s | FileCheck %s -check-prefixes=CHECK-SVE
+
+; Do not use SVE, NEON has a dedicated instruction for fixed vector
+define <8 x i8> @test_v8i8(<8 x i8> %a) {
+; CHECK-SVE-LABEL: test_v8i8:
+; CHECK-SVE: // %bb.0:
+; CHECK-SVE-NEXT: rbit v0.8b, v0.8b
+; CHECK-SVE-NEXT: ret
+ %r = call <8 x i8> @llvm.bitreverse(<8 x i8> %a)
+ ret <8 x i8> %r
+}
+
+; Do not use SVE, NEON has a dedicated instruction for fixed vector
+define <16 x i8> @test_v16i8(<16 x i8> %a) {
+; CHECK-SVE-LABEL: test_v16i8:
+; CHECK-SVE: // %bb.0:
+; CHECK-SVE-NEXT: rbit v0.16b, v0.16b
+; CHECK-SVE-NEXT: ret
+ %r = call <16 x i8> @llvm.bitreverse(<16 x i8> %a)
+ ret <16 x i8> %r
+}
+
+define <4 x i16> @test_v4i16(<4 x i16> %a) {
+; CHECK-SVE-LABEL: test_v4i16:
+; CHECK-SVE: // %bb.0:
+; CHECK-SVE-NEXT: rev16 v0.8b, v0.8b
+; CHECK-SVE-NEXT: rbit v0.8b, v0.8b
+; CHECK-SVE-NEXT: ret
+ %r = call <4 x i16> @llvm.bitreverse(<4 x i16> %a)
+ ret <4 x i16> %r
+}
+
+define <8 x i16> @test_v8i16(<8 x i16> %a) {
+; CHECK-SVE-LABEL: test_v8i16:
+; CHECK-SVE: // %bb.0:
+; CHECK-SVE-NEXT: rev16 v0.16b, v0.16b
+; CHECK-SVE-NEXT: rbit v0.16b, v0.16b
+; CHECK-SVE-NEXT: ret
+ %r = call <8 x i16> @llvm.bitreverse(<8 x i16> %a)
+ ret <8 x i16> %r
+}
+
+define <2 x i32> @test_v2i32(<2 x i32> %a) {
+; CHECK-SVE-LABEL: test_v2i32:
+; CHECK-SVE: // %bb.0:
+; CHECK-SVE-NEXT: rev32 v0.8b, v0.8b
+; CHECK-SVE-NEXT: rbit v0.8b, v0.8b
+; CHECK-SVE-NEXT: ret
+ %r = call <2 x i32> @llvm.bitreverse(<2 x i32> %a)
+ ret <2 x i32> %r
+}
+
+define <4 x i32> @test_v4i32(<4 x i32> %a) {
+; CHECK-SVE-LABEL: test_v4i32:
+; CHECK-SVE: // %bb.0:
+; CHECK-SVE-NEXT: rev32 v0.16b, v0.16b
+; CHECK-SVE-NEXT: rbit v0.16b, v0.16b
+; CHECK-SVE-NEXT: ret
+ %r = call <4 x i32> @llvm.bitreverse(<4 x i32> %a)
+ ret <4 x i32> %r
+}
+
+define <1 x i64> @test_v1i64(<1 x i64> %a) {
+; CHECK-SVE-LABEL: test_v1i64:
+; CHECK-SVE: // %bb.0:
+; CHECK-SVE-NEXT: rev64 v0.8b, v0.8b
+; CHECK-SVE-NEXT: rbit v0.8b, v0.8b
+; CHECK-SVE-NEXT: ret
+ %r = call <1 x i64> @llvm.bitreverse(<1 x i64> %a)
+ ret <1 x i64> %r
+}
+
+define <2 x i64> @test_v2i64(<2 x i64> %a) {
+; CHECK-SVE-LABEL: test_v2i64:
+; CHECK-SVE: // %bb.0:
+; CHECK-SVE-NEXT: rev64 v0.16b, v0.16b
+; CHECK-SVE-NEXT: rbit v0.16b, v0.16b
+; CHECK-SVE-NEXT: ret
+ %r = call <2 x i64> @llvm.bitreverse(<2 x i64> %a)
+ ret <2 x i64> %r
+}
>From 9a0d585d6df51f78d709acc733e1b0cada194f13 Mon Sep 17 00:00:00 2001
From: Harry Ramsey <harry.ramsey at arm.com>
Date: Thu, 7 May 2026 08:54:14 +0000
Subject: [PATCH 2/3] fixup! [AArch64][ISel] Prefer SVE over NEON for
fixed-width bitreverse
---
llvm/lib/Target/AArch64/AArch64ISelLowering.cpp | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index f5082b779d1db..78bbb8be2454b 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -1935,6 +1935,13 @@ AArch64TargetLowering::AArch64TargetLowering(const TargetMachine &TM,
setOperationAction(ISD::MUL, MVT::v1i64, Custom);
setOperationAction(ISD::MUL, MVT::v2i64, Custom);
+ // Neon doesn't have dedicated instructions for vectors of this size but SVE
+ // does.
+ for (auto VT :
+ {MVT::v4i16, MVT::v8i16, MVT::v2i32, MVT::v4i32, MVT::v2i64}) {
+ setOperationAction(ISD::BITREVERSE, VT, Custom);
+ }
+
// With SVE2 we can try lowering these to pairwise operations (e.g. smaxp).
if (Subtarget->hasSVE2() || Subtarget->isStreamingSVEAvailable()) {
setOperationAction(ISD::VECREDUCE_SMAX, MVT::v2i64, Custom);
@@ -11820,8 +11827,7 @@ SDValue AArch64TargetLowering::LowerBitreverse(SDValue Op,
EVT VT = Op.getValueType();
if (VT.isScalableVector() ||
- useSVEForFixedLengthVectorVT(
- VT, /*OverrideNEON=*/Subtarget->useSVEForFixedLengthVectors()))
+ useSVEForFixedLengthVectorVT(VT, /*OverrideNEON=*/true))
return LowerToPredicatedOp(Op, DAG, AArch64ISD::BITREVERSE_MERGE_PASSTHRU);
SDLoc DL(Op);
>From 167e36401a1ce3b9bacca599cbabcffdfabfe8b5 Mon Sep 17 00:00:00 2001
From: Harry Ramsey <harry.ramsey at arm.com>
Date: Thu, 7 May 2026 09:01:32 +0000
Subject: [PATCH 3/3] fixup! [AArch64][ISel] Prefer SVE over NEON for
fixed-width bitreverse
---
.../AArch64/sve-fixed-length-bitreverse.ll | 36 ++++++++++++-------
1 file changed, 24 insertions(+), 12 deletions(-)
diff --git a/llvm/test/CodeGen/AArch64/sve-fixed-length-bitreverse.ll b/llvm/test/CodeGen/AArch64/sve-fixed-length-bitreverse.ll
index b59ed2ff0c77a..e5308b2304509 100644
--- a/llvm/test/CodeGen/AArch64/sve-fixed-length-bitreverse.ll
+++ b/llvm/test/CodeGen/AArch64/sve-fixed-length-bitreverse.ll
@@ -24,8 +24,10 @@ define <16 x i8> @test_v16i8(<16 x i8> %a) {
define <4 x i16> @test_v4i16(<4 x i16> %a) {
; CHECK-SVE-LABEL: test_v4i16:
; CHECK-SVE: // %bb.0:
-; CHECK-SVE-NEXT: rev16 v0.8b, v0.8b
-; CHECK-SVE-NEXT: rbit v0.8b, v0.8b
+; CHECK-SVE-NEXT: ptrue p0.h, vl4
+; CHECK-SVE-NEXT: // kill: def $d0 killed $d0 def $z0
+; CHECK-SVE-NEXT: rbit z0.h, p0/m, z0.h
+; CHECK-SVE-NEXT: // kill: def $d0 killed $d0 killed $z0
; CHECK-SVE-NEXT: ret
%r = call <4 x i16> @llvm.bitreverse(<4 x i16> %a)
ret <4 x i16> %r
@@ -34,8 +36,10 @@ define <4 x i16> @test_v4i16(<4 x i16> %a) {
define <8 x i16> @test_v8i16(<8 x i16> %a) {
; CHECK-SVE-LABEL: test_v8i16:
; CHECK-SVE: // %bb.0:
-; CHECK-SVE-NEXT: rev16 v0.16b, v0.16b
-; CHECK-SVE-NEXT: rbit v0.16b, v0.16b
+; CHECK-SVE-NEXT: ptrue p0.h, vl8
+; CHECK-SVE-NEXT: // kill: def $q0 killed $q0 def $z0
+; CHECK-SVE-NEXT: rbit z0.h, p0/m, z0.h
+; CHECK-SVE-NEXT: // kill: def $q0 killed $q0 killed $z0
; CHECK-SVE-NEXT: ret
%r = call <8 x i16> @llvm.bitreverse(<8 x i16> %a)
ret <8 x i16> %r
@@ -44,8 +48,10 @@ define <8 x i16> @test_v8i16(<8 x i16> %a) {
define <2 x i32> @test_v2i32(<2 x i32> %a) {
; CHECK-SVE-LABEL: test_v2i32:
; CHECK-SVE: // %bb.0:
-; CHECK-SVE-NEXT: rev32 v0.8b, v0.8b
-; CHECK-SVE-NEXT: rbit v0.8b, v0.8b
+; CHECK-SVE-NEXT: ptrue p0.s, vl2
+; CHECK-SVE-NEXT: // kill: def $d0 killed $d0 def $z0
+; CHECK-SVE-NEXT: rbit z0.s, p0/m, z0.s
+; CHECK-SVE-NEXT: // kill: def $d0 killed $d0 killed $z0
; CHECK-SVE-NEXT: ret
%r = call <2 x i32> @llvm.bitreverse(<2 x i32> %a)
ret <2 x i32> %r
@@ -54,8 +60,10 @@ define <2 x i32> @test_v2i32(<2 x i32> %a) {
define <4 x i32> @test_v4i32(<4 x i32> %a) {
; CHECK-SVE-LABEL: test_v4i32:
; CHECK-SVE: // %bb.0:
-; CHECK-SVE-NEXT: rev32 v0.16b, v0.16b
-; CHECK-SVE-NEXT: rbit v0.16b, v0.16b
+; CHECK-SVE-NEXT: ptrue p0.s, vl4
+; CHECK-SVE-NEXT: // kill: def $q0 killed $q0 def $z0
+; CHECK-SVE-NEXT: rbit z0.s, p0/m, z0.s
+; CHECK-SVE-NEXT: // kill: def $q0 killed $q0 killed $z0
; CHECK-SVE-NEXT: ret
%r = call <4 x i32> @llvm.bitreverse(<4 x i32> %a)
ret <4 x i32> %r
@@ -64,8 +72,10 @@ define <4 x i32> @test_v4i32(<4 x i32> %a) {
define <1 x i64> @test_v1i64(<1 x i64> %a) {
; CHECK-SVE-LABEL: test_v1i64:
; CHECK-SVE: // %bb.0:
-; CHECK-SVE-NEXT: rev64 v0.8b, v0.8b
-; CHECK-SVE-NEXT: rbit v0.8b, v0.8b
+; CHECK-SVE-NEXT: ptrue p0.d, vl1
+; CHECK-SVE-NEXT: // kill: def $d0 killed $d0 def $z0
+; CHECK-SVE-NEXT: rbit z0.d, p0/m, z0.d
+; CHECK-SVE-NEXT: // kill: def $d0 killed $d0 killed $z0
; CHECK-SVE-NEXT: ret
%r = call <1 x i64> @llvm.bitreverse(<1 x i64> %a)
ret <1 x i64> %r
@@ -74,8 +84,10 @@ define <1 x i64> @test_v1i64(<1 x i64> %a) {
define <2 x i64> @test_v2i64(<2 x i64> %a) {
; CHECK-SVE-LABEL: test_v2i64:
; CHECK-SVE: // %bb.0:
-; CHECK-SVE-NEXT: rev64 v0.16b, v0.16b
-; CHECK-SVE-NEXT: rbit v0.16b, v0.16b
+; CHECK-SVE-NEXT: ptrue p0.d, vl2
+; CHECK-SVE-NEXT: // kill: def $q0 killed $q0 def $z0
+; CHECK-SVE-NEXT: rbit z0.d, p0/m, z0.d
+; CHECK-SVE-NEXT: // kill: def $q0 killed $q0 killed $z0
; CHECK-SVE-NEXT: ret
%r = call <2 x i64> @llvm.bitreverse(<2 x i64> %a)
ret <2 x i64> %r
More information about the llvm-commits
mailing list