[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