[llvm] [VectorCombine] fold nested bitreverse and bswap (PR #202236)

Kenny Lau via llvm-commits llvm-commits at lists.llvm.org
Fri Jun 12 12:57:12 PDT 2026


https://github.com/lauk20 updated https://github.com/llvm/llvm-project/pull/202236

>From ac5e7474fa41858cb00d1f4cce839eee4b4f06c9 Mon Sep 17 00:00:00 2001
From: Kenny <72945813+lauk20 at users.noreply.github.com>
Date: Sun, 7 Jun 2026 18:15:01 -0400
Subject: [PATCH 1/6] fold nested bitreverse and bswap

---
 .../InstCombine/InstCombineCalls.cpp          | 44 +++++++++++++
 .../InstCombine/bitreverse-bswap-fold.ll      | 63 +++++++++++++++++++
 2 files changed, 107 insertions(+)
 create mode 100644 llvm/test/Transforms/InstCombine/bitreverse-bswap-fold.ll

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index 7bcaa930511ee..4952f1a80c21c 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -1643,6 +1643,41 @@ static Instruction *foldBitOrderCrossLogicOp(Value *V,
   return nullptr;
 }
 
+/// Fold the following cases into a single byte-level bit-reverse operation 
+/// and accepts bswap and bitreverse intrinsics:
+///   bswap(bitreverse(x)) --> bitcast(bitreverse(bitcast(x)))
+///   bitreverse(bswap(x)) --> bitcast(bitreverse(bitcast(x)))
+template <Intrinsic::ID IntrID>
+static Value *foldBitOrderReverseAndSwap(IntrinsicInst *II,
+                                             InstCombiner::BuilderTy &Builder) {
+  static_assert(IntrID == Intrinsic::bswap || IntrID == Intrinsic::bitreverse,
+                "This helper only supports BSWAP and BITREVERSE intrinsics");
+
+  Value *Arg = II->getArgOperand(0);
+  Type *Ty = II->getType();
+
+  if (Ty->getScalarSizeInBits() <= 8)
+    return nullptr;
+
+  constexpr Intrinsic::ID ComplementID = (IntrID == Intrinsic::bitreverse) 
+                                 ? Intrinsic::bswap 
+                                 : Intrinsic::bitreverse;
+
+  Value *X;
+  if (match(Arg, m_OneUse(m_Intrinsic<ComplementID>(m_Value(X))))) {
+    unsigned TotalBits = Ty->getPrimitiveSizeInBits();
+    Type *I8Ty = Builder.getInt8Ty();
+    Type *NewVecTy = VectorType::get(I8Ty, ElementCount::getFixed(TotalBits / 8));
+
+    // Cast to <N x i8>, perform a bitreverse, and cast back
+    Value *CastIn = Builder.CreateBitCast(X, NewVecTy);
+    Value *NewCall = Builder.CreateUnaryIntrinsic(Intrinsic::bitreverse, CastIn);
+    return Builder.CreateBitCast(NewCall, Ty);
+  }
+
+  return nullptr;
+}
+
 /// Helper to match idempotent binary intrinsics, namely, intrinsics where
 /// `f(f(x, y), y) == f(x, y)` holds.
 static bool isIdempotentBinaryIntrinsic(Intrinsic::ID IID) {
@@ -2420,6 +2455,10 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
     if (Instruction *crossLogicOpFold =
         foldBitOrderCrossLogicOp<Intrinsic::bitreverse>(IIOperand, Builder))
       return crossLogicOpFold;
+    
+    if (Value *swapReverseSwapFold = 
+        foldBitOrderReverseAndSwap<Intrinsic::bitreverse>(II, Builder))
+      return replaceInstUsesWith(*II, swapReverseSwapFold);
 
     break;
   }
@@ -2476,6 +2515,11 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
     if (Instruction *BitOp = matchBSwapOrBitReverse(*II, /*MatchBSwaps*/ false,
                                                     /*MatchBitReversals*/ true))
       return BitOp;
+
+    if (Value *swapReverseSwapFold = 
+        foldBitOrderReverseAndSwap<Intrinsic::bswap>(II, Builder))
+      return replaceInstUsesWith(*II, swapReverseSwapFold);
+
     break;
   }
   case Intrinsic::masked_load:
diff --git a/llvm/test/Transforms/InstCombine/bitreverse-bswap-fold.ll b/llvm/test/Transforms/InstCombine/bitreverse-bswap-fold.ll
new file mode 100644
index 0000000000000..6c75a2a62c91d
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/bitreverse-bswap-fold.ll
@@ -0,0 +1,63 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -S -passes=instcombine < %s | FileCheck %s
+
+define i64 @fold_scalar_i64(i64 %0) {
+; CHECK-LABEL: define i64 @fold_scalar_i64(
+; CHECK-SAME: i64 [[TMP0:%.*]]) {
+; CHECK-NEXT:    [[TMP2:%.*]] = bitcast i64 [[TMP0]] to <8 x i8>
+; CHECK-NEXT:    [[TMP3:%.*]] = call <8 x i8> @llvm.bitreverse.v8i8(<8 x i8> [[TMP2]])
+; CHECK-NEXT:    [[T2:%.*]] = bitcast <8 x i8> [[TMP3]] to i64
+; CHECK-NEXT:    ret i64 [[T2]]
+;
+  %t1 = tail call i64 @llvm.bswap.i64(i64 %0)
+  %t2 = tail call i64 @llvm.bitreverse.i64(i64 %t1)
+  ret i64 %t2
+}
+
+define <2 x i64> @fold_vector_v2i64(<2 x i64> %0) {
+; CHECK-LABEL: define <2 x i64> @fold_vector_v2i64(
+; CHECK-SAME: <2 x i64> [[TMP0:%.*]]) {
+; CHECK-NEXT:    [[TMP2:%.*]] = bitcast <2 x i64> [[TMP0]] to <16 x i8>
+; CHECK-NEXT:    [[TMP3:%.*]] = call <16 x i8> @llvm.bitreverse.v16i8(<16 x i8> [[TMP2]])
+; CHECK-NEXT:    [[T2:%.*]] = bitcast <16 x i8> [[TMP3]] to <2 x i64>
+; CHECK-NEXT:    ret <2 x i64> [[T2]]
+;
+  %t1 = tail call <2 x i64> @llvm.bitreverse.v2i64(<2 x i64> %0)
+  %t2 = tail call <2 x i64> @llvm.bswap.v2i64(<2 x i64> %t1)
+  ret <2 x i64> %t2
+}
+
+define i32 @fold_scalar_i32(i32 %0) {
+; CHECK-LABEL: define i32 @fold_scalar_i32(
+; CHECK-SAME: i32 [[TMP0:%.*]]) {
+; CHECK-NEXT:    [[TMP2:%.*]] = bitcast i32 [[TMP0]] to <4 x i8>
+; CHECK-NEXT:    [[TMP3:%.*]] = call <4 x i8> @llvm.bitreverse.v4i8(<4 x i8> [[TMP2]])
+; CHECK-NEXT:    [[T2:%.*]] = bitcast <4 x i8> [[TMP3]] to i32
+; CHECK-NEXT:    ret i32 [[T2]]
+;
+  %t1 = tail call i32 @llvm.bswap.i32(i32 %0)
+  %t2 = tail call i32 @llvm.bitreverse.i32(i32 %t1)
+  ret i32 %t2
+}
+
+define <4 x i32> @fold_vector_v4i32(<4 x i32> %0) {
+; CHECK-LABEL: define <4 x i32> @fold_vector_v4i32(
+; CHECK-SAME: <4 x i32> [[TMP0:%.*]]) {
+; CHECK-NEXT:    [[TMP2:%.*]] = bitcast <4 x i32> [[TMP0]] to <16 x i8>
+; CHECK-NEXT:    [[TMP3:%.*]] = call <16 x i8> @llvm.bitreverse.v16i8(<16 x i8> [[TMP2]])
+; CHECK-NEXT:    [[T2:%.*]] = bitcast <16 x i8> [[TMP3]] to <4 x i32>
+; CHECK-NEXT:    ret <4 x i32> [[T2]]
+;
+  %t1 = tail call <4 x i32> @llvm.bswap.v4i32(<4 x i32> %0)
+  %t2 = tail call <4 x i32> @llvm.bitreverse.v4i32(<4 x i32> %t1)
+  ret <4 x i32> %t2
+}
+
+declare i64 @llvm.bswap.i64(i64)
+declare i64 @llvm.bitreverse.i64(i64)
+declare <2 x i64> @llvm.bswap.v2i64(<2 x i64>)
+declare <2 x i64> @llvm.bitreverse.v2i64(<2 x i64>)
+declare i32 @llvm.bswap.i32(i32)
+declare i32 @llvm.bitreverse.i32(i32)
+declare <4 x i32> @llvm.bswap.v4i32(<4 x i32>)
+declare <4 x i32> @llvm.bitreverse.v4i32(<4 x i32>)

>From c3b0b7c05ec9aeb6ca033c39c54550f456a63d37 Mon Sep 17 00:00:00 2001
From: Kenny <72945813+lauk20 at users.noreply.github.com>
Date: Sun, 7 Jun 2026 18:35:39 -0400
Subject: [PATCH 2/6] update clang-format

---
 .../InstCombine/InstCombineCalls.cpp          | 26 ++++++++++---------
 1 file changed, 14 insertions(+), 12 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index 4952f1a80c21c..70be1af6ee445 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -1643,13 +1643,13 @@ static Instruction *foldBitOrderCrossLogicOp(Value *V,
   return nullptr;
 }
 
-/// Fold the following cases into a single byte-level bit-reverse operation 
+/// Fold the following cases into a single byte-level bit-reverse operation
 /// and accepts bswap and bitreverse intrinsics:
 ///   bswap(bitreverse(x)) --> bitcast(bitreverse(bitcast(x)))
 ///   bitreverse(bswap(x)) --> bitcast(bitreverse(bitcast(x)))
 template <Intrinsic::ID IntrID>
 static Value *foldBitOrderReverseAndSwap(IntrinsicInst *II,
-                                             InstCombiner::BuilderTy &Builder) {
+                                         InstCombiner::BuilderTy &Builder) {
   static_assert(IntrID == Intrinsic::bswap || IntrID == Intrinsic::bitreverse,
                 "This helper only supports BSWAP and BITREVERSE intrinsics");
 
@@ -1659,19 +1659,21 @@ static Value *foldBitOrderReverseAndSwap(IntrinsicInst *II,
   if (Ty->getScalarSizeInBits() <= 8)
     return nullptr;
 
-  constexpr Intrinsic::ID ComplementID = (IntrID == Intrinsic::bitreverse) 
-                                 ? Intrinsic::bswap 
-                                 : Intrinsic::bitreverse;
+  constexpr Intrinsic::ID ComplementID = (IntrID == Intrinsic::bitreverse)
+                                             ? Intrinsic::bswap
+                                             : Intrinsic::bitreverse;
 
   Value *X;
   if (match(Arg, m_OneUse(m_Intrinsic<ComplementID>(m_Value(X))))) {
     unsigned TotalBits = Ty->getPrimitiveSizeInBits();
     Type *I8Ty = Builder.getInt8Ty();
-    Type *NewVecTy = VectorType::get(I8Ty, ElementCount::getFixed(TotalBits / 8));
+    Type *NewVecTy =
+        VectorType::get(I8Ty, ElementCount::getFixed(TotalBits / 8));
 
     // Cast to <N x i8>, perform a bitreverse, and cast back
     Value *CastIn = Builder.CreateBitCast(X, NewVecTy);
-    Value *NewCall = Builder.CreateUnaryIntrinsic(Intrinsic::bitreverse, CastIn);
+    Value *NewCall =
+        Builder.CreateUnaryIntrinsic(Intrinsic::bitreverse, CastIn);
     return Builder.CreateBitCast(NewCall, Ty);
   }
 
@@ -2455,9 +2457,9 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
     if (Instruction *crossLogicOpFold =
         foldBitOrderCrossLogicOp<Intrinsic::bitreverse>(IIOperand, Builder))
       return crossLogicOpFold;
-    
-    if (Value *swapReverseSwapFold = 
-        foldBitOrderReverseAndSwap<Intrinsic::bitreverse>(II, Builder))
+
+    if (Value *swapReverseSwapFold =
+            foldBitOrderReverseAndSwap<Intrinsic::bitreverse>(II, Builder))
       return replaceInstUsesWith(*II, swapReverseSwapFold);
 
     break;
@@ -2516,8 +2518,8 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
                                                     /*MatchBitReversals*/ true))
       return BitOp;
 
-    if (Value *swapReverseSwapFold = 
-        foldBitOrderReverseAndSwap<Intrinsic::bswap>(II, Builder))
+    if (Value *swapReverseSwapFold =
+            foldBitOrderReverseAndSwap<Intrinsic::bswap>(II, Builder))
       return replaceInstUsesWith(*II, swapReverseSwapFold);
 
     break;

>From 12811cba60c38a32499d46f53abbab5b156566b9 Mon Sep 17 00:00:00 2001
From: Kenny <72945813+lauk20 at users.noreply.github.com>
Date: Sun, 7 Jun 2026 22:25:35 -0400
Subject: [PATCH 3/6] fix scalable vectors (no folding)

---
 .../Transforms/InstCombine/InstCombineCalls.cpp    |  6 ++++++
 .../InstCombine/bitreverse-bswap-fold.ll           | 14 ++++++++++++++
 2 files changed, 20 insertions(+)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index 70be1af6ee445..415db2bee94df 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -1656,6 +1656,12 @@ static Value *foldBitOrderReverseAndSwap(IntrinsicInst *II,
   Value *Arg = II->getArgOperand(0);
   Type *Ty = II->getType();
 
+  if (auto *VecTy = dyn_cast<VectorType>(Ty)) {
+    auto VecEltCnt = VecTy->getElementCount();
+    if (VecEltCnt.isScalable())
+      return nullptr;
+  }
+
   if (Ty->getScalarSizeInBits() <= 8)
     return nullptr;
 
diff --git a/llvm/test/Transforms/InstCombine/bitreverse-bswap-fold.ll b/llvm/test/Transforms/InstCombine/bitreverse-bswap-fold.ll
index 6c75a2a62c91d..4be9b43ad10a6 100644
--- a/llvm/test/Transforms/InstCombine/bitreverse-bswap-fold.ll
+++ b/llvm/test/Transforms/InstCombine/bitreverse-bswap-fold.ll
@@ -53,6 +53,18 @@ define <4 x i32> @fold_vector_v4i32(<4 x i32> %0) {
   ret <4 x i32> %t2
 }
 
+define <vscale x 2 x i16> @no_fold_scalable(<vscale x 2 x i16> %x) {
+; CHECK-LABEL: define <vscale x 2 x i16> @no_fold_scalable(
+; CHECK-SAME: <vscale x 2 x i16> [[X:%.*]]) {
+; CHECK-NEXT:    [[T1:%.*]] = call <vscale x 2 x i16> @llvm.bswap.nxv2i16(<vscale x 2 x i16> [[X]])
+; CHECK-NEXT:    [[T2:%.*]] = call <vscale x 2 x i16> @llvm.bitreverse.nxv2i16(<vscale x 2 x i16> [[T1]])
+; CHECK-NEXT:    ret <vscale x 2 x i16> [[T2]]
+;
+  %t1 = call <vscale x 2 x i16> @llvm.bswap.nxv2i16(<vscale x 2 x i16> %x)
+  %t2 = call <vscale x 2 x i16> @llvm.bitreverse.nxv2i16(<vscale x 2 x i16> %t1)
+  ret <vscale x 2 x i16> %t2
+}
+
 declare i64 @llvm.bswap.i64(i64)
 declare i64 @llvm.bitreverse.i64(i64)
 declare <2 x i64> @llvm.bswap.v2i64(<2 x i64>)
@@ -61,3 +73,5 @@ declare i32 @llvm.bswap.i32(i32)
 declare i32 @llvm.bitreverse.i32(i32)
 declare <4 x i32> @llvm.bswap.v4i32(<4 x i32>)
 declare <4 x i32> @llvm.bitreverse.v4i32(<4 x i32>)
+declare <vscale x 2 x i16> @llvm.bswap.nxv2i16(<vscale x 2 x i16>)
+declare <vscale x 2 x i16> @llvm.bitreverse.nxv2i16(<vscale x 2 x i16>)

>From 67bb81fcc6bcec0845a83aa7a2412cb6b9130e7d Mon Sep 17 00:00:00 2001
From: Kenny <72945813+lauk20 at users.noreply.github.com>
Date: Mon, 8 Jun 2026 15:05:24 -0400
Subject: [PATCH 4/6] move implementation to VectorCombine

---
 .../InstCombine/InstCombineCalls.cpp          | 52 ------------
 .../Transforms/Vectorize/VectorCombine.cpp    | 82 +++++++++++++++++++
 .../AArch64/fold-bitreverse-bswap-fold.ll}    | 12 ++-
 .../X86/fold-bitreverse-bswap-fold.ll         | 75 +++++++++++++++++
 4 files changed, 162 insertions(+), 59 deletions(-)
 rename llvm/test/Transforms/{InstCombine/bitreverse-bswap-fold.ll => VectorCombine/AArch64/fold-bitreverse-bswap-fold.ll} (85%)
 create mode 100644 llvm/test/Transforms/VectorCombine/X86/fold-bitreverse-bswap-fold.ll

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index 415db2bee94df..7bcaa930511ee 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -1643,49 +1643,6 @@ static Instruction *foldBitOrderCrossLogicOp(Value *V,
   return nullptr;
 }
 
-/// Fold the following cases into a single byte-level bit-reverse operation
-/// and accepts bswap and bitreverse intrinsics:
-///   bswap(bitreverse(x)) --> bitcast(bitreverse(bitcast(x)))
-///   bitreverse(bswap(x)) --> bitcast(bitreverse(bitcast(x)))
-template <Intrinsic::ID IntrID>
-static Value *foldBitOrderReverseAndSwap(IntrinsicInst *II,
-                                         InstCombiner::BuilderTy &Builder) {
-  static_assert(IntrID == Intrinsic::bswap || IntrID == Intrinsic::bitreverse,
-                "This helper only supports BSWAP and BITREVERSE intrinsics");
-
-  Value *Arg = II->getArgOperand(0);
-  Type *Ty = II->getType();
-
-  if (auto *VecTy = dyn_cast<VectorType>(Ty)) {
-    auto VecEltCnt = VecTy->getElementCount();
-    if (VecEltCnt.isScalable())
-      return nullptr;
-  }
-
-  if (Ty->getScalarSizeInBits() <= 8)
-    return nullptr;
-
-  constexpr Intrinsic::ID ComplementID = (IntrID == Intrinsic::bitreverse)
-                                             ? Intrinsic::bswap
-                                             : Intrinsic::bitreverse;
-
-  Value *X;
-  if (match(Arg, m_OneUse(m_Intrinsic<ComplementID>(m_Value(X))))) {
-    unsigned TotalBits = Ty->getPrimitiveSizeInBits();
-    Type *I8Ty = Builder.getInt8Ty();
-    Type *NewVecTy =
-        VectorType::get(I8Ty, ElementCount::getFixed(TotalBits / 8));
-
-    // Cast to <N x i8>, perform a bitreverse, and cast back
-    Value *CastIn = Builder.CreateBitCast(X, NewVecTy);
-    Value *NewCall =
-        Builder.CreateUnaryIntrinsic(Intrinsic::bitreverse, CastIn);
-    return Builder.CreateBitCast(NewCall, Ty);
-  }
-
-  return nullptr;
-}
-
 /// Helper to match idempotent binary intrinsics, namely, intrinsics where
 /// `f(f(x, y), y) == f(x, y)` holds.
 static bool isIdempotentBinaryIntrinsic(Intrinsic::ID IID) {
@@ -2464,10 +2421,6 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
         foldBitOrderCrossLogicOp<Intrinsic::bitreverse>(IIOperand, Builder))
       return crossLogicOpFold;
 
-    if (Value *swapReverseSwapFold =
-            foldBitOrderReverseAndSwap<Intrinsic::bitreverse>(II, Builder))
-      return replaceInstUsesWith(*II, swapReverseSwapFold);
-
     break;
   }
   case Intrinsic::bswap: {
@@ -2523,11 +2476,6 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
     if (Instruction *BitOp = matchBSwapOrBitReverse(*II, /*MatchBSwaps*/ false,
                                                     /*MatchBitReversals*/ true))
       return BitOp;
-
-    if (Value *swapReverseSwapFold =
-            foldBitOrderReverseAndSwap<Intrinsic::bswap>(II, Builder))
-      return replaceInstUsesWith(*II, swapReverseSwapFold);
-
     break;
   }
   case Intrinsic::masked_load:
diff --git a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
index db812745f1df5..f7099ab242aa3 100644
--- a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
+++ b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
@@ -157,6 +157,7 @@ class VectorCombine {
   bool foldInterleaveIntrinsics(Instruction &I);
   bool foldDeinterleaveIntrinsics(Instruction &I);
   bool foldBitcastOfVPLoad(Instruction &I);
+  bool foldBitOrderReverseAndSwap(Instruction &I);
   bool shrinkType(Instruction &I);
   bool shrinkLoadForShuffles(Instruction &I);
   bool shrinkPhiOfShuffles(Instruction &I);
@@ -5907,6 +5908,81 @@ bool VectorCombine::foldBitcastOfVPLoad(Instruction &I) {
   return true;
 }
 
+/// Fold the following cases into a single byte-level bit-reverse operation
+/// and accepts bswap and bitreverse intrinsics:
+///   bswap(bitreverse(x)) --> bitcast(bitreverse(bitcast(x)))
+///   bitreverse(bswap(x)) --> bitcast(bitreverse(bitcast(x)))
+bool VectorCombine::foldBitOrderReverseAndSwap(Instruction &I) {
+  auto *II = dyn_cast<IntrinsicInst>(&I);
+  if (!II)
+    return false;
+
+  Intrinsic::ID IntrID = II->getIntrinsicID();
+  if (IntrID != Intrinsic::bitreverse && IntrID != Intrinsic::bswap)
+    return false;
+
+  // No fold on scalable vectors
+  Type *Ty = II->getType();
+  if (auto *VecTy = dyn_cast<VectorType>(Ty)) {
+    if (VecTy->getElementCount().isScalable())
+      return false;
+  }
+
+  if (Ty->getScalarSizeInBits() <= 8)
+    return false;
+
+  Intrinsic::ID ComplementID = (IntrID == Intrinsic::bitreverse)
+                                   ? Intrinsic::bswap
+                                   : Intrinsic::bitreverse;
+
+  Value *Arg = II->getArgOperand(0);
+  Value *X;
+  if (ComplementID == Intrinsic::bswap) {
+    if (!match(Arg, m_OneUse(m_Intrinsic<Intrinsic::bswap>(m_Value(X)))))
+      return false;
+  } else {
+    if (!match(Arg, m_OneUse(m_Intrinsic<Intrinsic::bitreverse>(m_Value(X)))))
+      return false;
+  }
+
+  unsigned TotalBits = Ty->getPrimitiveSizeInBits();
+  Type *I8Ty = Builder.getInt8Ty();
+  Type *NewVecTy = VectorType::get(I8Ty, ElementCount::getFixed(TotalBits / 8));
+
+  // OldCost = cost of bitreverse/bswap + cost of bswap/bitreverse
+  IntrinsicCostAttributes ICAOld1(ComplementID, Ty, {Ty});
+  IntrinsicCostAttributes ICAOld2(IntrID, Ty, {Ty});
+  InstructionCost OldCost = TTI.getIntrinsicInstrCost(ICAOld1, CostKind) +
+                            TTI.getIntrinsicInstrCost(ICAOld2, CostKind);
+
+  // NewCost = cost of bitcast to byte vector +
+  //           cost of bitreverse/bswap on byte vector +
+  //           cost of bitcast back to original type
+  InstructionCost CastToVecCost = TTI.getCastInstrCost(
+      Instruction::BitCast, NewVecTy, Ty, TTI::CastContextHint::None, CostKind);
+  InstructionCost CastToOrigCost = TTI.getCastInstrCost(
+      Instruction::BitCast, Ty, NewVecTy, TTI::CastContextHint::None, CostKind);
+
+  IntrinsicCostAttributes ICANew(Intrinsic::bitreverse, NewVecTy, {NewVecTy});
+  InstructionCost NewIntrinsicCost =
+      TTI.getIntrinsicInstrCost(ICANew, CostKind);
+  InstructionCost NewCost = CastToVecCost + NewIntrinsicCost + CastToOrigCost;
+
+  LLVM_DEBUG(dbgs() << "foldBitOrderReverseAndSwap: OldCost=" << OldCost
+                    << " NewCost=" << NewCost << "\n");
+  if (!NewCost.isValid() || NewCost > OldCost)
+    return false;
+
+  // Perform transform: bitcast(arg, <N x i8>), bitreverse, bitcast back
+  Builder.SetInsertPoint(II);
+  Value *CastToVec = Builder.CreateBitCast(X, NewVecTy);
+  Value *NewCall =
+      Builder.CreateUnaryIntrinsic(Intrinsic::bitreverse, CastToVec);
+  Value *CastToOrig = Builder.CreateBitCast(NewCall, Ty);
+  replaceValue(I, *CastToOrig);
+  return true;
+}
+
 // Attempt to shrink loads that are only used by shufflevector instructions.
 bool VectorCombine::shrinkLoadForShuffles(Instruction &I) {
   auto *OldLoad = dyn_cast<LoadInst>(&I);
@@ -6259,6 +6335,10 @@ bool VectorCombine::run() {
         if (shrinkPhiOfShuffles(I))
           return true;
         break;
+      case Instruction::Call:
+        if (foldBitOrderReverseAndSwap(I))
+          return true;
+        break;
       default:
         if (shrinkType(I))
           return true;
@@ -6271,6 +6351,8 @@ bool VectorCombine::run() {
           return true;
         if (foldCastFromReductions(I))
           return true;
+        if (foldBitOrderReverseAndSwap(I))
+          return true;
         break;
       case Instruction::ExtractElement:
         if (foldShuffleChainsToReduce(I))
diff --git a/llvm/test/Transforms/InstCombine/bitreverse-bswap-fold.ll b/llvm/test/Transforms/VectorCombine/AArch64/fold-bitreverse-bswap-fold.ll
similarity index 85%
rename from llvm/test/Transforms/InstCombine/bitreverse-bswap-fold.ll
rename to llvm/test/Transforms/VectorCombine/AArch64/fold-bitreverse-bswap-fold.ll
index 4be9b43ad10a6..5cc96d4ecc4ca 100644
--- a/llvm/test/Transforms/InstCombine/bitreverse-bswap-fold.ll
+++ b/llvm/test/Transforms/VectorCombine/AArch64/fold-bitreverse-bswap-fold.ll
@@ -1,12 +1,11 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
-; RUN: opt -S -passes=instcombine < %s | FileCheck %s
+; RUN: opt -S -passes=vector-combine -mtriple=aarch64 < %s | FileCheck %s
 
 define i64 @fold_scalar_i64(i64 %0) {
 ; CHECK-LABEL: define i64 @fold_scalar_i64(
 ; CHECK-SAME: i64 [[TMP0:%.*]]) {
-; CHECK-NEXT:    [[TMP2:%.*]] = bitcast i64 [[TMP0]] to <8 x i8>
-; CHECK-NEXT:    [[TMP3:%.*]] = call <8 x i8> @llvm.bitreverse.v8i8(<8 x i8> [[TMP2]])
-; CHECK-NEXT:    [[T2:%.*]] = bitcast <8 x i8> [[TMP3]] to i64
+; CHECK-NEXT:    [[T1:%.*]] = tail call i64 @llvm.bswap.i64(i64 [[TMP0]])
+; CHECK-NEXT:    [[T2:%.*]] = tail call i64 @llvm.bitreverse.i64(i64 [[T1]])
 ; CHECK-NEXT:    ret i64 [[T2]]
 ;
   %t1 = tail call i64 @llvm.bswap.i64(i64 %0)
@@ -30,9 +29,8 @@ define <2 x i64> @fold_vector_v2i64(<2 x i64> %0) {
 define i32 @fold_scalar_i32(i32 %0) {
 ; CHECK-LABEL: define i32 @fold_scalar_i32(
 ; CHECK-SAME: i32 [[TMP0:%.*]]) {
-; CHECK-NEXT:    [[TMP2:%.*]] = bitcast i32 [[TMP0]] to <4 x i8>
-; CHECK-NEXT:    [[TMP3:%.*]] = call <4 x i8> @llvm.bitreverse.v4i8(<4 x i8> [[TMP2]])
-; CHECK-NEXT:    [[T2:%.*]] = bitcast <4 x i8> [[TMP3]] to i32
+; CHECK-NEXT:    [[T1:%.*]] = tail call i32 @llvm.bswap.i32(i32 [[TMP0]])
+; CHECK-NEXT:    [[T2:%.*]] = tail call i32 @llvm.bitreverse.i32(i32 [[T1]])
 ; CHECK-NEXT:    ret i32 [[T2]]
 ;
   %t1 = tail call i32 @llvm.bswap.i32(i32 %0)
diff --git a/llvm/test/Transforms/VectorCombine/X86/fold-bitreverse-bswap-fold.ll b/llvm/test/Transforms/VectorCombine/X86/fold-bitreverse-bswap-fold.ll
new file mode 100644
index 0000000000000..217e9709b28ae
--- /dev/null
+++ b/llvm/test/Transforms/VectorCombine/X86/fold-bitreverse-bswap-fold.ll
@@ -0,0 +1,75 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -S -passes=vector-combine -mtriple=x86_64 < %s | FileCheck %s
+
+define i64 @fold_scalar_i64(i64 %0) {
+; CHECK-LABEL: define i64 @fold_scalar_i64(
+; CHECK-SAME: i64 [[TMP0:%.*]]) {
+; CHECK-NEXT:    [[T1:%.*]] = tail call i64 @llvm.bswap.i64(i64 [[TMP0]])
+; CHECK-NEXT:    [[T2:%.*]] = tail call i64 @llvm.bitreverse.i64(i64 [[T1]])
+; CHECK-NEXT:    ret i64 [[T2]]
+;
+  %t1 = tail call i64 @llvm.bswap.i64(i64 %0)
+  %t2 = tail call i64 @llvm.bitreverse.i64(i64 %t1)
+  ret i64 %t2
+}
+
+define <2 x i64> @fold_vector_v2i64(<2 x i64> %0) {
+; CHECK-LABEL: define <2 x i64> @fold_vector_v2i64(
+; CHECK-SAME: <2 x i64> [[TMP0:%.*]]) {
+; CHECK-NEXT:    [[TMP2:%.*]] = bitcast <2 x i64> [[TMP0]] to <16 x i8>
+; CHECK-NEXT:    [[TMP3:%.*]] = call <16 x i8> @llvm.bitreverse.v16i8(<16 x i8> [[TMP2]])
+; CHECK-NEXT:    [[T2:%.*]] = bitcast <16 x i8> [[TMP3]] to <2 x i64>
+; CHECK-NEXT:    ret <2 x i64> [[T2]]
+;
+  %t1 = tail call <2 x i64> @llvm.bitreverse.v2i64(<2 x i64> %0)
+  %t2 = tail call <2 x i64> @llvm.bswap.v2i64(<2 x i64> %t1)
+  ret <2 x i64> %t2
+}
+
+define i32 @fold_scalar_i32(i32 %0) {
+; CHECK-LABEL: define i32 @fold_scalar_i32(
+; CHECK-SAME: i32 [[TMP0:%.*]]) {
+; CHECK-NEXT:    [[T1:%.*]] = tail call i32 @llvm.bswap.i32(i32 [[TMP0]])
+; CHECK-NEXT:    [[T2:%.*]] = tail call i32 @llvm.bitreverse.i32(i32 [[T1]])
+; CHECK-NEXT:    ret i32 [[T2]]
+;
+  %t1 = tail call i32 @llvm.bswap.i32(i32 %0)
+  %t2 = tail call i32 @llvm.bitreverse.i32(i32 %t1)
+  ret i32 %t2
+}
+
+define <4 x i32> @fold_vector_v4i32(<4 x i32> %0) {
+; CHECK-LABEL: define <4 x i32> @fold_vector_v4i32(
+; CHECK-SAME: <4 x i32> [[TMP0:%.*]]) {
+; CHECK-NEXT:    [[TMP2:%.*]] = bitcast <4 x i32> [[TMP0]] to <16 x i8>
+; CHECK-NEXT:    [[TMP3:%.*]] = call <16 x i8> @llvm.bitreverse.v16i8(<16 x i8> [[TMP2]])
+; CHECK-NEXT:    [[T2:%.*]] = bitcast <16 x i8> [[TMP3]] to <4 x i32>
+; CHECK-NEXT:    ret <4 x i32> [[T2]]
+;
+  %t1 = tail call <4 x i32> @llvm.bswap.v4i32(<4 x i32> %0)
+  %t2 = tail call <4 x i32> @llvm.bitreverse.v4i32(<4 x i32> %t1)
+  ret <4 x i32> %t2
+}
+
+define <vscale x 2 x i16> @no_fold_scalable(<vscale x 2 x i16> %x) {
+; CHECK-LABEL: define <vscale x 2 x i16> @no_fold_scalable(
+; CHECK-SAME: <vscale x 2 x i16> [[X:%.*]]) {
+; CHECK-NEXT:    [[T1:%.*]] = call <vscale x 2 x i16> @llvm.bswap.nxv2i16(<vscale x 2 x i16> [[X]])
+; CHECK-NEXT:    [[T2:%.*]] = call <vscale x 2 x i16> @llvm.bitreverse.nxv2i16(<vscale x 2 x i16> [[T1]])
+; CHECK-NEXT:    ret <vscale x 2 x i16> [[T2]]
+;
+  %t1 = call <vscale x 2 x i16> @llvm.bswap.nxv2i16(<vscale x 2 x i16> %x)
+  %t2 = call <vscale x 2 x i16> @llvm.bitreverse.nxv2i16(<vscale x 2 x i16> %t1)
+  ret <vscale x 2 x i16> %t2
+}
+
+declare i64 @llvm.bswap.i64(i64)
+declare i64 @llvm.bitreverse.i64(i64)
+declare <2 x i64> @llvm.bswap.v2i64(<2 x i64>)
+declare <2 x i64> @llvm.bitreverse.v2i64(<2 x i64>)
+declare i32 @llvm.bswap.i32(i32)
+declare i32 @llvm.bitreverse.i32(i32)
+declare <4 x i32> @llvm.bswap.v4i32(<4 x i32>)
+declare <4 x i32> @llvm.bitreverse.v4i32(<4 x i32>)
+declare <vscale x 2 x i16> @llvm.bswap.nxv2i16(<vscale x 2 x i16>)
+declare <vscale x 2 x i16> @llvm.bitreverse.nxv2i16(<vscale x 2 x i16>)

>From 5289f70438ae749e453e0a92679bfb9bf1185ec5 Mon Sep 17 00:00:00 2001
From: Kenny <72945813+lauk20 at users.noreply.github.com>
Date: Tue, 9 Jun 2026 14:33:44 -0400
Subject: [PATCH 5/6] cleaned up code - moved OneUse to cost modeling stage

---
 .../Transforms/Vectorize/VectorCombine.cpp    | 35 ++++++++-----------
 .../AArch64/fold-bitreverse-bswap-fold.ll     | 13 +------
 .../X86/fold-bitreverse-bswap-fold.ll         | 13 +------
 3 files changed, 16 insertions(+), 45 deletions(-)

diff --git a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
index f7099ab242aa3..2a289a0c5b929 100644
--- a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
+++ b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
@@ -5928,32 +5928,21 @@ bool VectorCombine::foldBitOrderReverseAndSwap(Instruction &I) {
       return false;
   }
 
-  if (Ty->getScalarSizeInBits() <= 8)
-    return false;
-
-  Intrinsic::ID ComplementID = (IntrID == Intrinsic::bitreverse)
-                                   ? Intrinsic::bswap
-                                   : Intrinsic::bitreverse;
-
-  Value *Arg = II->getArgOperand(0);
   Value *X;
-  if (ComplementID == Intrinsic::bswap) {
-    if (!match(Arg, m_OneUse(m_Intrinsic<Intrinsic::bswap>(m_Value(X)))))
-      return false;
-  } else {
-    if (!match(Arg, m_OneUse(m_Intrinsic<Intrinsic::bitreverse>(m_Value(X)))))
-      return false;
-  }
+  if (!match(II, m_Intrinsic<Intrinsic::bitreverse>(
+                     m_Intrinsic<Intrinsic::bswap>(m_Value(X)))) &&
+      !match(II, m_Intrinsic<Intrinsic::bswap>(
+                     m_Intrinsic<Intrinsic::bitreverse>(m_Value(X)))))
+    return false;
 
   unsigned TotalBits = Ty->getPrimitiveSizeInBits();
   Type *I8Ty = Builder.getInt8Ty();
   Type *NewVecTy = VectorType::get(I8Ty, ElementCount::getFixed(TotalBits / 8));
 
+  auto InnerII = cast<IntrinsicInst>(II->getArgOperand(0));
   // OldCost = cost of bitreverse/bswap + cost of bswap/bitreverse
-  IntrinsicCostAttributes ICAOld1(ComplementID, Ty, {Ty});
-  IntrinsicCostAttributes ICAOld2(IntrID, Ty, {Ty});
-  InstructionCost OldCost = TTI.getIntrinsicInstrCost(ICAOld1, CostKind) +
-                            TTI.getIntrinsicInstrCost(ICAOld2, CostKind);
+  InstructionCost OldCost = TTI.getInstructionCost(II, CostKind) +
+                            TTI.getInstructionCost(InnerII, CostKind);
 
   // NewCost = cost of bitcast to byte vector +
   //           cost of bitreverse/bswap on byte vector +
@@ -5968,8 +5957,12 @@ bool VectorCombine::foldBitOrderReverseAndSwap(Instruction &I) {
       TTI.getIntrinsicInstrCost(ICANew, CostKind);
   InstructionCost NewCost = CastToVecCost + NewIntrinsicCost + CastToOrigCost;
 
-  LLVM_DEBUG(dbgs() << "foldBitOrderReverseAndSwap: OldCost=" << OldCost
-                    << " NewCost=" << NewCost << "\n");
+  if (!InnerII->hasOneUse())
+    NewCost += TTI.getInstructionCost(InnerII, CostKind);
+
+  LLVM_DEBUG(dbgs() << "Found bitorder reverse and swap: " << I
+                    << "\n  OldCost: " << OldCost << " vs NewCost: " << NewCost
+                    << "\n");
   if (!NewCost.isValid() || NewCost > OldCost)
     return false;
 
diff --git a/llvm/test/Transforms/VectorCombine/AArch64/fold-bitreverse-bswap-fold.ll b/llvm/test/Transforms/VectorCombine/AArch64/fold-bitreverse-bswap-fold.ll
index 5cc96d4ecc4ca..feaf5c9cd9c28 100644
--- a/llvm/test/Transforms/VectorCombine/AArch64/fold-bitreverse-bswap-fold.ll
+++ b/llvm/test/Transforms/VectorCombine/AArch64/fold-bitreverse-bswap-fold.ll
@@ -61,15 +61,4 @@ define <vscale x 2 x i16> @no_fold_scalable(<vscale x 2 x i16> %x) {
   %t1 = call <vscale x 2 x i16> @llvm.bswap.nxv2i16(<vscale x 2 x i16> %x)
   %t2 = call <vscale x 2 x i16> @llvm.bitreverse.nxv2i16(<vscale x 2 x i16> %t1)
   ret <vscale x 2 x i16> %t2
-}
-
-declare i64 @llvm.bswap.i64(i64)
-declare i64 @llvm.bitreverse.i64(i64)
-declare <2 x i64> @llvm.bswap.v2i64(<2 x i64>)
-declare <2 x i64> @llvm.bitreverse.v2i64(<2 x i64>)
-declare i32 @llvm.bswap.i32(i32)
-declare i32 @llvm.bitreverse.i32(i32)
-declare <4 x i32> @llvm.bswap.v4i32(<4 x i32>)
-declare <4 x i32> @llvm.bitreverse.v4i32(<4 x i32>)
-declare <vscale x 2 x i16> @llvm.bswap.nxv2i16(<vscale x 2 x i16>)
-declare <vscale x 2 x i16> @llvm.bitreverse.nxv2i16(<vscale x 2 x i16>)
+}
\ No newline at end of file
diff --git a/llvm/test/Transforms/VectorCombine/X86/fold-bitreverse-bswap-fold.ll b/llvm/test/Transforms/VectorCombine/X86/fold-bitreverse-bswap-fold.ll
index 217e9709b28ae..42a6e12a6668a 100644
--- a/llvm/test/Transforms/VectorCombine/X86/fold-bitreverse-bswap-fold.ll
+++ b/llvm/test/Transforms/VectorCombine/X86/fold-bitreverse-bswap-fold.ll
@@ -61,15 +61,4 @@ define <vscale x 2 x i16> @no_fold_scalable(<vscale x 2 x i16> %x) {
   %t1 = call <vscale x 2 x i16> @llvm.bswap.nxv2i16(<vscale x 2 x i16> %x)
   %t2 = call <vscale x 2 x i16> @llvm.bitreverse.nxv2i16(<vscale x 2 x i16> %t1)
   ret <vscale x 2 x i16> %t2
-}
-
-declare i64 @llvm.bswap.i64(i64)
-declare i64 @llvm.bitreverse.i64(i64)
-declare <2 x i64> @llvm.bswap.v2i64(<2 x i64>)
-declare <2 x i64> @llvm.bitreverse.v2i64(<2 x i64>)
-declare i32 @llvm.bswap.i32(i32)
-declare i32 @llvm.bitreverse.i32(i32)
-declare <4 x i32> @llvm.bswap.v4i32(<4 x i32>)
-declare <4 x i32> @llvm.bitreverse.v4i32(<4 x i32>)
-declare <vscale x 2 x i16> @llvm.bswap.nxv2i16(<vscale x 2 x i16>)
-declare <vscale x 2 x i16> @llvm.bitreverse.nxv2i16(<vscale x 2 x i16>)
+}
\ No newline at end of file

>From c059d35fe37006c3ed540e943d2b451ea387f6d9 Mon Sep 17 00:00:00 2001
From: Kenny <72945813+lauk20 at users.noreply.github.com>
Date: Fri, 12 Jun 2026 15:54:58 -0400
Subject: [PATCH 6/6] handle scalable vectors

---
 .../Transforms/Vectorize/VectorCombine.cpp    | 25 +++++-----
 .../AArch64/fold-bitreverse-bswap-fold.ll     | 40 +++++++++++++--
 .../X86/fold-bitreverse-bswap-fold.ll         | 49 ++++++++++++-------
 3 files changed, 81 insertions(+), 33 deletions(-)

diff --git a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
index 2a289a0c5b929..da067889a6aa3 100644
--- a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
+++ b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
@@ -5917,17 +5917,6 @@ bool VectorCombine::foldBitOrderReverseAndSwap(Instruction &I) {
   if (!II)
     return false;
 
-  Intrinsic::ID IntrID = II->getIntrinsicID();
-  if (IntrID != Intrinsic::bitreverse && IntrID != Intrinsic::bswap)
-    return false;
-
-  // No fold on scalable vectors
-  Type *Ty = II->getType();
-  if (auto *VecTy = dyn_cast<VectorType>(Ty)) {
-    if (VecTy->getElementCount().isScalable())
-      return false;
-  }
-
   Value *X;
   if (!match(II, m_Intrinsic<Intrinsic::bitreverse>(
                      m_Intrinsic<Intrinsic::bswap>(m_Value(X)))) &&
@@ -5935,9 +5924,19 @@ bool VectorCombine::foldBitOrderReverseAndSwap(Instruction &I) {
                      m_Intrinsic<Intrinsic::bitreverse>(m_Value(X)))))
     return false;
 
-  unsigned TotalBits = Ty->getPrimitiveSizeInBits();
+  Type *Ty = II->getType();
   Type *I8Ty = Builder.getInt8Ty();
-  Type *NewVecTy = VectorType::get(I8Ty, ElementCount::getFixed(TotalBits / 8));
+  Type *NewVecTy;
+
+  if (auto *VecTy = dyn_cast<VectorType>(Ty)) {
+    unsigned ElementSize =
+        VecTy->getElementType()->getPrimitiveSizeInBits() / 8;
+    ElementCount NewVecCnt = VecTy->getElementCount() * ElementSize;
+    NewVecTy = VectorType::get(I8Ty, NewVecCnt);
+  } else {
+    unsigned TotalBits = Ty->getPrimitiveSizeInBits();
+    NewVecTy = VectorType::get(I8Ty, ElementCount::getFixed(TotalBits / 8));
+  }
 
   auto InnerII = cast<IntrinsicInst>(II->getArgOperand(0));
   // OldCost = cost of bitreverse/bswap + cost of bswap/bitreverse
diff --git a/llvm/test/Transforms/VectorCombine/AArch64/fold-bitreverse-bswap-fold.ll b/llvm/test/Transforms/VectorCombine/AArch64/fold-bitreverse-bswap-fold.ll
index feaf5c9cd9c28..35a2d4f5134d4 100644
--- a/llvm/test/Transforms/VectorCombine/AArch64/fold-bitreverse-bswap-fold.ll
+++ b/llvm/test/Transforms/VectorCombine/AArch64/fold-bitreverse-bswap-fold.ll
@@ -1,5 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
 ; RUN: opt -S -passes=vector-combine -mtriple=aarch64 < %s | FileCheck %s
+; RUN: opt -S -passes=vector-combine -mtriple=aarch64 -mattr=+sve2 < %s | FileCheck %s --check-prefix=SVE2
 
 define i64 @fold_scalar_i64(i64 %0) {
 ; CHECK-LABEL: define i64 @fold_scalar_i64(
@@ -7,6 +8,12 @@ define i64 @fold_scalar_i64(i64 %0) {
 ; CHECK-NEXT:    [[T1:%.*]] = tail call i64 @llvm.bswap.i64(i64 [[TMP0]])
 ; CHECK-NEXT:    [[T2:%.*]] = tail call i64 @llvm.bitreverse.i64(i64 [[T1]])
 ; CHECK-NEXT:    ret i64 [[T2]]
+;
+; SVE2-LABEL: define i64 @fold_scalar_i64(
+; SVE2-SAME: i64 [[TMP0:%.*]]) #[[ATTR0:[0-9]+]] {
+; SVE2-NEXT:    [[T1:%.*]] = tail call i64 @llvm.bswap.i64(i64 [[TMP0]])
+; SVE2-NEXT:    [[T2:%.*]] = tail call i64 @llvm.bitreverse.i64(i64 [[T1]])
+; SVE2-NEXT:    ret i64 [[T2]]
 ;
   %t1 = tail call i64 @llvm.bswap.i64(i64 %0)
   %t2 = tail call i64 @llvm.bitreverse.i64(i64 %t1)
@@ -20,6 +27,13 @@ define <2 x i64> @fold_vector_v2i64(<2 x i64> %0) {
 ; CHECK-NEXT:    [[TMP3:%.*]] = call <16 x i8> @llvm.bitreverse.v16i8(<16 x i8> [[TMP2]])
 ; CHECK-NEXT:    [[T2:%.*]] = bitcast <16 x i8> [[TMP3]] to <2 x i64>
 ; CHECK-NEXT:    ret <2 x i64> [[T2]]
+;
+; SVE2-LABEL: define <2 x i64> @fold_vector_v2i64(
+; SVE2-SAME: <2 x i64> [[TMP0:%.*]]) #[[ATTR0]] {
+; SVE2-NEXT:    [[TMP2:%.*]] = bitcast <2 x i64> [[TMP0]] to <16 x i8>
+; SVE2-NEXT:    [[TMP3:%.*]] = call <16 x i8> @llvm.bitreverse.v16i8(<16 x i8> [[TMP2]])
+; SVE2-NEXT:    [[T2:%.*]] = bitcast <16 x i8> [[TMP3]] to <2 x i64>
+; SVE2-NEXT:    ret <2 x i64> [[T2]]
 ;
   %t1 = tail call <2 x i64> @llvm.bitreverse.v2i64(<2 x i64> %0)
   %t2 = tail call <2 x i64> @llvm.bswap.v2i64(<2 x i64> %t1)
@@ -32,6 +46,12 @@ define i32 @fold_scalar_i32(i32 %0) {
 ; CHECK-NEXT:    [[T1:%.*]] = tail call i32 @llvm.bswap.i32(i32 [[TMP0]])
 ; CHECK-NEXT:    [[T2:%.*]] = tail call i32 @llvm.bitreverse.i32(i32 [[T1]])
 ; CHECK-NEXT:    ret i32 [[T2]]
+;
+; SVE2-LABEL: define i32 @fold_scalar_i32(
+; SVE2-SAME: i32 [[TMP0:%.*]]) #[[ATTR0]] {
+; SVE2-NEXT:    [[T1:%.*]] = tail call i32 @llvm.bswap.i32(i32 [[TMP0]])
+; SVE2-NEXT:    [[T2:%.*]] = tail call i32 @llvm.bitreverse.i32(i32 [[T1]])
+; SVE2-NEXT:    ret i32 [[T2]]
 ;
   %t1 = tail call i32 @llvm.bswap.i32(i32 %0)
   %t2 = tail call i32 @llvm.bitreverse.i32(i32 %t1)
@@ -45,20 +65,34 @@ define <4 x i32> @fold_vector_v4i32(<4 x i32> %0) {
 ; CHECK-NEXT:    [[TMP3:%.*]] = call <16 x i8> @llvm.bitreverse.v16i8(<16 x i8> [[TMP2]])
 ; CHECK-NEXT:    [[T2:%.*]] = bitcast <16 x i8> [[TMP3]] to <4 x i32>
 ; CHECK-NEXT:    ret <4 x i32> [[T2]]
+;
+; SVE2-LABEL: define <4 x i32> @fold_vector_v4i32(
+; SVE2-SAME: <4 x i32> [[TMP0:%.*]]) #[[ATTR0]] {
+; SVE2-NEXT:    [[TMP2:%.*]] = bitcast <4 x i32> [[TMP0]] to <16 x i8>
+; SVE2-NEXT:    [[TMP3:%.*]] = call <16 x i8> @llvm.bitreverse.v16i8(<16 x i8> [[TMP2]])
+; SVE2-NEXT:    [[T2:%.*]] = bitcast <16 x i8> [[TMP3]] to <4 x i32>
+; SVE2-NEXT:    ret <4 x i32> [[T2]]
 ;
   %t1 = tail call <4 x i32> @llvm.bswap.v4i32(<4 x i32> %0)
   %t2 = tail call <4 x i32> @llvm.bitreverse.v4i32(<4 x i32> %t1)
   ret <4 x i32> %t2
 }
 
-define <vscale x 2 x i16> @no_fold_scalable(<vscale x 2 x i16> %x) {
-; CHECK-LABEL: define <vscale x 2 x i16> @no_fold_scalable(
+define <vscale x 2 x i16> @fold_scalable(<vscale x 2 x i16> %x) {
+; CHECK-LABEL: define <vscale x 2 x i16> @fold_scalable(
 ; CHECK-SAME: <vscale x 2 x i16> [[X:%.*]]) {
 ; CHECK-NEXT:    [[T1:%.*]] = call <vscale x 2 x i16> @llvm.bswap.nxv2i16(<vscale x 2 x i16> [[X]])
 ; CHECK-NEXT:    [[T2:%.*]] = call <vscale x 2 x i16> @llvm.bitreverse.nxv2i16(<vscale x 2 x i16> [[T1]])
 ; CHECK-NEXT:    ret <vscale x 2 x i16> [[T2]]
+;
+; SVE2-LABEL: define <vscale x 2 x i16> @fold_scalable(
+; SVE2-SAME: <vscale x 2 x i16> [[X:%.*]]) #[[ATTR0]] {
+; SVE2-NEXT:    [[TMP1:%.*]] = bitcast <vscale x 2 x i16> [[X]] to <vscale x 4 x i8>
+; SVE2-NEXT:    [[TMP2:%.*]] = call <vscale x 4 x i8> @llvm.bitreverse.nxv4i8(<vscale x 4 x i8> [[TMP1]])
+; SVE2-NEXT:    [[T2:%.*]] = bitcast <vscale x 4 x i8> [[TMP2]] to <vscale x 2 x i16>
+; SVE2-NEXT:    ret <vscale x 2 x i16> [[T2]]
 ;
   %t1 = call <vscale x 2 x i16> @llvm.bswap.nxv2i16(<vscale x 2 x i16> %x)
   %t2 = call <vscale x 2 x i16> @llvm.bitreverse.nxv2i16(<vscale x 2 x i16> %t1)
   ret <vscale x 2 x i16> %t2
-}
\ No newline at end of file
+}
diff --git a/llvm/test/Transforms/VectorCombine/X86/fold-bitreverse-bswap-fold.ll b/llvm/test/Transforms/VectorCombine/X86/fold-bitreverse-bswap-fold.ll
index 42a6e12a6668a..5aa820095467a 100644
--- a/llvm/test/Transforms/VectorCombine/X86/fold-bitreverse-bswap-fold.ll
+++ b/llvm/test/Transforms/VectorCombine/X86/fold-bitreverse-bswap-fold.ll
@@ -1,12 +1,20 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
-; RUN: opt -S -passes=vector-combine -mtriple=x86_64 < %s | FileCheck %s
+; RUN: opt < %s -passes=vector-combine -S -mtriple=x86_64-- -mattr=SSE2 | FileCheck %s --check-prefixes=CHECK,SSE
+; RUN: opt < %s -passes=vector-combine -S -mtriple=x86_64-- -mattr=AVX2 | FileCheck %s --check-prefixes=CHECK,AVX
 
 define i64 @fold_scalar_i64(i64 %0) {
-; CHECK-LABEL: define i64 @fold_scalar_i64(
-; CHECK-SAME: i64 [[TMP0:%.*]]) {
-; CHECK-NEXT:    [[T1:%.*]] = tail call i64 @llvm.bswap.i64(i64 [[TMP0]])
-; CHECK-NEXT:    [[T2:%.*]] = tail call i64 @llvm.bitreverse.i64(i64 [[T1]])
-; CHECK-NEXT:    ret i64 [[T2]]
+; SSE-LABEL: define i64 @fold_scalar_i64(
+; SSE-SAME: i64 [[TMP0:%.*]]) #[[ATTR0:[0-9]+]] {
+; SSE-NEXT:    [[T1:%.*]] = tail call i64 @llvm.bswap.i64(i64 [[TMP0]])
+; SSE-NEXT:    [[T2:%.*]] = tail call i64 @llvm.bitreverse.i64(i64 [[T1]])
+; SSE-NEXT:    ret i64 [[T2]]
+;
+; AVX-LABEL: define i64 @fold_scalar_i64(
+; AVX-SAME: i64 [[TMP0:%.*]]) #[[ATTR0:[0-9]+]] {
+; AVX-NEXT:    [[TMP2:%.*]] = bitcast i64 [[TMP0]] to <8 x i8>
+; AVX-NEXT:    [[TMP3:%.*]] = call <8 x i8> @llvm.bitreverse.v8i8(<8 x i8> [[TMP2]])
+; AVX-NEXT:    [[T2:%.*]] = bitcast <8 x i8> [[TMP3]] to i64
+; AVX-NEXT:    ret i64 [[T2]]
 ;
   %t1 = tail call i64 @llvm.bswap.i64(i64 %0)
   %t2 = tail call i64 @llvm.bitreverse.i64(i64 %t1)
@@ -15,7 +23,7 @@ define i64 @fold_scalar_i64(i64 %0) {
 
 define <2 x i64> @fold_vector_v2i64(<2 x i64> %0) {
 ; CHECK-LABEL: define <2 x i64> @fold_vector_v2i64(
-; CHECK-SAME: <2 x i64> [[TMP0:%.*]]) {
+; CHECK-SAME: <2 x i64> [[TMP0:%.*]]) #[[ATTR0:[0-9]+]] {
 ; CHECK-NEXT:    [[TMP2:%.*]] = bitcast <2 x i64> [[TMP0]] to <16 x i8>
 ; CHECK-NEXT:    [[TMP3:%.*]] = call <16 x i8> @llvm.bitreverse.v16i8(<16 x i8> [[TMP2]])
 ; CHECK-NEXT:    [[T2:%.*]] = bitcast <16 x i8> [[TMP3]] to <2 x i64>
@@ -27,11 +35,18 @@ define <2 x i64> @fold_vector_v2i64(<2 x i64> %0) {
 }
 
 define i32 @fold_scalar_i32(i32 %0) {
-; CHECK-LABEL: define i32 @fold_scalar_i32(
-; CHECK-SAME: i32 [[TMP0:%.*]]) {
-; CHECK-NEXT:    [[T1:%.*]] = tail call i32 @llvm.bswap.i32(i32 [[TMP0]])
-; CHECK-NEXT:    [[T2:%.*]] = tail call i32 @llvm.bitreverse.i32(i32 [[T1]])
-; CHECK-NEXT:    ret i32 [[T2]]
+; SSE-LABEL: define i32 @fold_scalar_i32(
+; SSE-SAME: i32 [[TMP0:%.*]]) #[[ATTR0]] {
+; SSE-NEXT:    [[T1:%.*]] = tail call i32 @llvm.bswap.i32(i32 [[TMP0]])
+; SSE-NEXT:    [[T2:%.*]] = tail call i32 @llvm.bitreverse.i32(i32 [[T1]])
+; SSE-NEXT:    ret i32 [[T2]]
+;
+; AVX-LABEL: define i32 @fold_scalar_i32(
+; AVX-SAME: i32 [[TMP0:%.*]]) #[[ATTR0]] {
+; AVX-NEXT:    [[TMP2:%.*]] = bitcast i32 [[TMP0]] to <4 x i8>
+; AVX-NEXT:    [[TMP3:%.*]] = call <4 x i8> @llvm.bitreverse.v4i8(<4 x i8> [[TMP2]])
+; AVX-NEXT:    [[T2:%.*]] = bitcast <4 x i8> [[TMP3]] to i32
+; AVX-NEXT:    ret i32 [[T2]]
 ;
   %t1 = tail call i32 @llvm.bswap.i32(i32 %0)
   %t2 = tail call i32 @llvm.bitreverse.i32(i32 %t1)
@@ -40,7 +55,7 @@ define i32 @fold_scalar_i32(i32 %0) {
 
 define <4 x i32> @fold_vector_v4i32(<4 x i32> %0) {
 ; CHECK-LABEL: define <4 x i32> @fold_vector_v4i32(
-; CHECK-SAME: <4 x i32> [[TMP0:%.*]]) {
+; CHECK-SAME: <4 x i32> [[TMP0:%.*]]) #[[ATTR0]] {
 ; CHECK-NEXT:    [[TMP2:%.*]] = bitcast <4 x i32> [[TMP0]] to <16 x i8>
 ; CHECK-NEXT:    [[TMP3:%.*]] = call <16 x i8> @llvm.bitreverse.v16i8(<16 x i8> [[TMP2]])
 ; CHECK-NEXT:    [[T2:%.*]] = bitcast <16 x i8> [[TMP3]] to <4 x i32>
@@ -51,9 +66,9 @@ define <4 x i32> @fold_vector_v4i32(<4 x i32> %0) {
   ret <4 x i32> %t2
 }
 
-define <vscale x 2 x i16> @no_fold_scalable(<vscale x 2 x i16> %x) {
-; CHECK-LABEL: define <vscale x 2 x i16> @no_fold_scalable(
-; CHECK-SAME: <vscale x 2 x i16> [[X:%.*]]) {
+define <vscale x 2 x i16> @fold_scalable(<vscale x 2 x i16> %x) {
+; CHECK-LABEL: define <vscale x 2 x i16> @fold_scalable(
+; CHECK-SAME: <vscale x 2 x i16> [[X:%.*]]) #[[ATTR0]] {
 ; CHECK-NEXT:    [[T1:%.*]] = call <vscale x 2 x i16> @llvm.bswap.nxv2i16(<vscale x 2 x i16> [[X]])
 ; CHECK-NEXT:    [[T2:%.*]] = call <vscale x 2 x i16> @llvm.bitreverse.nxv2i16(<vscale x 2 x i16> [[T1]])
 ; CHECK-NEXT:    ret <vscale x 2 x i16> [[T2]]
@@ -61,4 +76,4 @@ define <vscale x 2 x i16> @no_fold_scalable(<vscale x 2 x i16> %x) {
   %t1 = call <vscale x 2 x i16> @llvm.bswap.nxv2i16(<vscale x 2 x i16> %x)
   %t2 = call <vscale x 2 x i16> @llvm.bitreverse.nxv2i16(<vscale x 2 x i16> %t1)
   ret <vscale x 2 x i16> %t2
-}
\ No newline at end of file
+}



More information about the llvm-commits mailing list