[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